<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.17">
<meta name="author" content="By Juan Monetta">
<title>FlowStorm debugger User&#8217;s Guide</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
/* Uncomment the following line when using as a custom stylesheet */
/* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
html{font-family:sans-serif;-webkit-text-size-adjust:100%}
a{background:none}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
b,strong{font-weight:bold}
abbr{font-size:.9em}
abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}
dfn{font-style:italic}
hr{height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
audio,video{display:inline-block}
audio:not([controls]){display:none;height:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type=checkbox],input[type=radio]{padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,::before,::after{box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:0}
p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt{background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
:not(pre).nobreak{word-wrap:normal}
:not(pre).nowrap{white-space:nowrap}
:not(pre).pre-wrap{white-space:pre-wrap}
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
pre>code{display:block}
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
details{margin-left:1.25rem}
details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}
details>summary::-webkit-details-marker{display:none}
details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}
details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}
details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.prettyprint{background:#f7f7f8}
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
pre.prettyprint li code[data-lang]::before{opacity:1}
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
table.linenotable td.code{padding-left:.75em}
table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
pre.pygments span.linenos{display:inline-block;margin-right:.75em}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}
td.tableblock>.content>:last-child{margin-bottom:-1.25em}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>*>tr>*{border-width:1px}
table.grid-cols>*>tr>*{border-width:0 1px}
table.grid-rows>*>tr>*{border-width:1px 0}
table.frame-all{border-width:1px}
table.frame-ends{border-width:1px 0}
table.frame-sides{border-width:0 1px}
table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}
table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}
table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}
table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}
table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
li>p:empty:only-child::before{content:"";display:inline-block}
ul.checklist>li>p:first-child{margin-left:-1em}
ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}
ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
td.hdlist2{word-wrap:anywhere}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background:#00fafa}
.black{color:#000}
.black-background{background:#000}
.blue{color:#0000bf}
.blue-background{background:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background:#fa00fa}
.gray{color:#606060}
.gray-background{background:#7d7d7d}
.green{color:#006000}
.green-background{background:#007d00}
.lime{color:#00bf00}
.lime-background{background:#00fa00}
.maroon{color:#600000}
.maroon-background{background:#7d0000}
.navy{color:#000060}
.navy-background{background:#00007d}
.olive{color:#606000}
.olive-background{background:#7d7d00}
.purple{color:#600060}
.purple-background{background:#7d007d}
.red{color:#bf0000}
.red-background{background:#fa0000}
.silver{color:#909090}
.silver-background{background:#bcbcbc}
.teal{color:#006060}
.teal-background{background:#007d7d}
.white{color:#bfbfbf}
.white-background{background:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt,summary{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]{border-bottom:1px dotted}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#header,#content,#footnotes,#footer{max-width:none}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
<style>
pre.rouge table td { padding: 5px; }
pre.rouge table pre { margin: 0; }
pre.rouge .cm {
  color: #999988;
  font-style: italic;
}
pre.rouge .cp {
  color: #999999;
  font-weight: bold;
}
pre.rouge .c1 {
  color: #999988;
  font-style: italic;
}
pre.rouge .cs {
  color: #999999;
  font-weight: bold;
  font-style: italic;
}
pre.rouge .c, pre.rouge .ch, pre.rouge .cd, pre.rouge .cpf {
  color: #999988;
  font-style: italic;
}
pre.rouge .err {
  color: #a61717;
  background-color: #e3d2d2;
}
pre.rouge .gd {
  color: #000000;
  background-color: #ffdddd;
}
pre.rouge .ge {
  color: #000000;
  font-style: italic;
}
pre.rouge .gr {
  color: #aa0000;
}
pre.rouge .gh {
  color: #999999;
}
pre.rouge .gi {
  color: #000000;
  background-color: #ddffdd;
}
pre.rouge .go {
  color: #888888;
}
pre.rouge .gp {
  color: #555555;
}
pre.rouge .gs {
  font-weight: bold;
}
pre.rouge .gu {
  color: #aaaaaa;
}
pre.rouge .gt {
  color: #aa0000;
}
pre.rouge .kc {
  color: #000000;
  font-weight: bold;
}
pre.rouge .kd {
  color: #000000;
  font-weight: bold;
}
pre.rouge .kn {
  color: #000000;
  font-weight: bold;
}
pre.rouge .kp {
  color: #000000;
  font-weight: bold;
}
pre.rouge .kr {
  color: #000000;
  font-weight: bold;
}
pre.rouge .kt {
  color: #445588;
  font-weight: bold;
}
pre.rouge .k, pre.rouge .kv {
  color: #000000;
  font-weight: bold;
}
pre.rouge .mf {
  color: #009999;
}
pre.rouge .mh {
  color: #009999;
}
pre.rouge .il {
  color: #009999;
}
pre.rouge .mi {
  color: #009999;
}
pre.rouge .mo {
  color: #009999;
}
pre.rouge .m, pre.rouge .mb, pre.rouge .mx {
  color: #009999;
}
pre.rouge .sa {
  color: #000000;
  font-weight: bold;
}
pre.rouge .sb {
  color: #d14;
}
pre.rouge .sc {
  color: #d14;
}
pre.rouge .sd {
  color: #d14;
}
pre.rouge .s2 {
  color: #d14;
}
pre.rouge .se {
  color: #d14;
}
pre.rouge .sh {
  color: #d14;
}
pre.rouge .si {
  color: #d14;
}
pre.rouge .sx {
  color: #d14;
}
pre.rouge .sr {
  color: #009926;
}
pre.rouge .s1 {
  color: #d14;
}
pre.rouge .ss {
  color: #990073;
}
pre.rouge .s, pre.rouge .dl {
  color: #d14;
}
pre.rouge .na {
  color: #008080;
}
pre.rouge .bp {
  color: #999999;
}
pre.rouge .nb {
  color: #0086B3;
}
pre.rouge .nc {
  color: #445588;
  font-weight: bold;
}
pre.rouge .no {
  color: #008080;
}
pre.rouge .nd {
  color: #3c5d5d;
  font-weight: bold;
}
pre.rouge .ni {
  color: #800080;
}
pre.rouge .ne {
  color: #990000;
  font-weight: bold;
}
pre.rouge .nf, pre.rouge .fm {
  color: #990000;
  font-weight: bold;
}
pre.rouge .nl {
  color: #990000;
  font-weight: bold;
}
pre.rouge .nn {
  color: #555555;
}
pre.rouge .nt {
  color: #000080;
}
pre.rouge .vc {
  color: #008080;
}
pre.rouge .vg {
  color: #008080;
}
pre.rouge .vi {
  color: #008080;
}
pre.rouge .nv, pre.rouge .vm {
  color: #008080;
}
pre.rouge .ow {
  color: #000000;
  font-weight: bold;
}
pre.rouge .o {
  color: #000000;
  font-weight: bold;
}
pre.rouge .w {
  color: #bbbbbb;
}
pre.rouge {
  background-color: #f8f8f8;
}
</style>
</head>
<body class="book toc2 toc-left">
<div id="header">
<h1>FlowStorm debugger User&#8217;s Guide</h1>
<div class="details">
<span id="author" class="author">By Juan Monetta</span><br>
</div>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#_quick_start">1. Quick start</a>
<ul class="sectlevel2">
<li><a href="#_clojure">1.1. Clojure</a>
<ul class="sectlevel3">
<li><a href="#_clojurestorm">1.1.1. ClojureStorm</a></li>
<li><a href="#_vanilla_flowstorm">1.1.2. Vanilla FlowStorm</a></li>
</ul>
</li>
<li><a href="#_clojurescript">1.2. ClojureScript</a>
<ul class="sectlevel3">
<li><a href="#_clojurescriptstorm_with_shadow_cljs">1.2.1. ClojureScriptStorm with shadow-cljs</a></li>
<li><a href="#_clojurescriptstorm_with_cljs_main">1.2.2. ClojureScriptStorm with cljs.main</a></li>
<li><a href="#_clojurescript_vanilla_flowstorm">1.2.3. ClojureScript vanilla FlowStorm</a></li>
<li><a href="#_multiple_clojurescript_builds">1.2.4. Multiple ClojureScript builds</a></li>
</ul>
</li>
<li><a href="#_babashka">1.3. Babashka</a></li>
</ul>
</li>
<li><a href="#_the_tool_bar">2. The tool bar</a></li>
<li><a href="#_flows_tool">3. Flows tool</a>
<ul class="sectlevel2">
<li><a href="#_code_tool">3.1. Code tool</a>
<ul class="sectlevel3">
<li><a href="#_code_stepping">3.1.1. Code stepping</a></li>
<li><a href="#_power_stepping">3.1.2. Power stepping</a></li>
<li><a href="#_searching">3.1.3. Searching</a></li>
<li><a href="#_loops">3.1.4. Loops</a></li>
<li><a href="#_exceptions_debugging">3.1.5. Exceptions debugging</a></li>
<li><a href="#_locals">3.1.6. Locals</a></li>
<li><a href="#_stack">3.1.7. Stack</a></li>
<li><a href="#_value_panels">3.1.8. Value panels</a></li>
<li><a href="#_goto_to_fileline">3.1.9. Goto to file:line</a></li>
</ul>
</li>
<li><a href="#_call_stack_tree_tool">3.2. Call Stack tree tool</a></li>
<li><a href="#_functions_tool">3.3. Functions tool</a>
<ul class="sectlevel3">
<li><a href="#_function_calls">3.3.1. Function calls</a></li>
</ul>
</li>
<li><a href="#_multi_thread_timeline">3.4. Multi-thread timeline</a></li>
<li><a href="#_printer">3.5. Printer</a></li>
<li><a href="#_bookmarks">3.6. Bookmarks</a>
<ul class="sectlevel3">
<li><a href="#_code_bookmarks">3.6.1. Code bookmarks</a></li>
<li><a href="#_ui_bookmarks">3.6.2. UI bookmarks</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_browser_tool">4. Browser tool</a></li>
<li><a href="#_outputs_tool">5. Outputs tool</a>
<ul class="sectlevel2">
<li><a href="#_middleware_setup">5.1. Middleware setup</a></li>
<li><a href="#_output_data_window">5.2. Output data window</a></li>
<li><a href="#_last_evals">5.3. Last evals</a></li>
<li><a href="#_taps">5.4. Taps</a></li>
<li><a href="#_out_and_err_streams">5.5. Out and Err streams</a></li>
</ul>
</li>
<li><a href="#_data_windows">6. Data Windows</a>
<ul class="sectlevel2">
<li><a href="#_data_navigation">6.1. Data navigation</a></li>
<li><a href="#_metadata_navigation">6.2. Metadata navigation</a></li>
<li><a href="#_multiple_visualizers">6.3. Multiple visualizers</a></li>
<li><a href="#_sequences">6.4. Sequences</a></li>
<li><a href="#_defining_values">6.5. Defining values</a></li>
<li><a href="#_realtime_visualizations">6.6. Realtime visualizations</a></li>
<li><a href="#_clojure_datafynav">6.7. Clojure datafy/nav</a></li>
<li><a href="#_eql_pprint_visualizer">6.8. EQL pprint visualizer</a></li>
<li><a href="#_custom_visualizers">6.9. Custom visualizers</a>
<ul class="sectlevel3">
<li><a href="#_data_aspect_extraction">6.9.1. Data aspect extraction</a></li>
<li><a href="#_visualizers">6.9.2. Visualizers</a></li>
<li><a href="#_clojurescript_2">6.9.3. ClojureScript</a></li>
</ul>
</li>
<li><a href="#_default_visualizers">6.10. Default visualizers</a></li>
</ul>
</li>
<li><a href="#_thread_breakpoints">7. Thread breakpoints</a></li>
<li><a href="#_programmable_debugging">8. Programmable debugging</a>
<ul class="sectlevel2">
<li><a href="#_timelines">8.1. Timelines</a></li>
<li><a href="#_forms">8.2. Forms</a></li>
<li><a href="#_multi_thread_timeline_2">8.3. Multi-thread timeline</a></li>
<li><a href="#_other_utilities">8.4. Other utilities</a></li>
</ul>
</li>
<li><a href="#_llm_agents">9. LLM agents</a></li>
<li><a href="#_remote_debugging">10. Remote debugging</a>
<ul class="sectlevel2">
<li><a href="#_ssh_tunnel">10.1. SSH tunnel</a></li>
<li><a href="#_out_of_process">10.2. Out of process</a></li>
<li><a href="#_docker">10.3. Docker</a></li>
</ul>
</li>
<li><a href="#_dealing_with_too_many_traces">11. Dealing with too many traces</a>
<ul class="sectlevel2">
<li><a href="#_fn_call_limits">11.1. Fn call limits</a></li>
<li><a href="#_trace_and_heap_limits">11.2. Trace and heap limits</a>
<ul class="sectlevel3">
<li><a href="#_trace_limits">11.2.1. Trace limits</a></li>
<li><a href="#_heap_limits">11.2.2. Heap limits</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_dealing_with_mutable_values">12. Dealing with mutable values</a></li>
<li><a href="#_controlling_instrumentation">13. Controlling instrumentation</a>
<ul class="sectlevel2">
<li><a href="#_turning_instrumentation_on_an_off">13.1. Turning instrumentation on an off</a></li>
<li><a href="#_setup_startup_instrumentation">13.2. Setup startup instrumentation</a></li>
<li><a href="#_modifying_instrumentation_with_the_browser">13.3. Modifying instrumentation with the Browser</a></li>
<li><a href="#_instrumentation_in_vanilla_flowstorm">13.4. Instrumentation in Vanilla FlowStorm</a>
<ul class="sectlevel3">
<li><a href="#_instrument_any_form_with_trace">13.4.1. Instrument any form with #trace</a></li>
<li><a href="#_run_code_with_rtrace">13.4.2. Run code with #rtrace</a></li>
<li><a href="#_instrument_namespaces">13.4.3. Instrument namespaces</a></li>
<li><a href="#_what_cant_be_instrumented">13.4.4. What can&#8217;t be instrumented?</a></li>
<li><a href="#_un_instrument_code">13.4.5. Un-instrument code</a></li>
<li><a href="#_instrument_with_the_browser">13.4.6. Instrument with the browser</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_plugins">14. Plugins</a>
<ul class="sectlevel2">
<li><a href="#_using_plugins">14.1. Using plugins</a></li>
<li><a href="#_creating_plugins">14.2. Creating plugins</a>
<ul class="sectlevel3">
<li><a href="#_runtime">14.2.1. Runtime</a></li>
<li><a href="#_ui">14.2.2. UI</a></li>
</ul>
</li>
<li><a href="#_list_of_known_plugins">14.3. List of known plugins</a></li>
</ul>
</li>
<li><a href="#_jvm_options_list">15. JVM options list</a>
<ul class="sectlevel2">
<li><a href="#_clojure_and_clojurescript">15.1. Clojure and ClojureScript</a></li>
<li><a href="#_only_clojure">15.2. Only Clojure</a></li>
<li><a href="#_only_clojurescript">15.3. Only ClojureScript</a></li>
</ul>
</li>
<li><a href="#_styling_and_theming">16. Styling and theming</a></li>
<li><a href="#_controlling_logging">17. Controlling logging</a></li>
<li><a href="#_key_bindings">18. Key bindings</a>
<ul class="sectlevel2">
<li><a href="#_general">18.1. General</a></li>
<li><a href="#_flows">18.2. Flows</a></li>
</ul>
</li>
<li><a href="#_debugging_react_native_applications">19. Debugging react native applications</a></li>
<li><a href="#_working_on_windows_with_wsl2">20. Working on Windows with WSL2</a></li>
<li><a href="#_opening_forms_in_editors">21. Opening forms in editors</a>
<ul class="sectlevel2">
<li><a href="#_emacs">21.1. Emacs</a></li>
<li><a href="#_vscode">21.2. VSCode</a></li>
<li><a href="#_intellij">21.3. IntelliJ</a></li>
<li><a href="#_vim">21.4. Vim</a></li>
</ul>
</li>
<li><a href="#_editorsides_integration">22. Editors/IDEs integration</a>
<ul class="sectlevel2">
<li><a href="#_emacs_2">22.1. Emacs</a></li>
<li><a href="#_vscode_2">22.2. VSCode</a></li>
<li><a href="#_intellij_idea_cursive">22.3. IntelliJ IDEA (Cursive)</a></li>
</ul>
</li>
<li><a href="#_tutorials_and_demos">23. Tutorials and demos</a></li>
<li><a href="#_known_limitations_and_issues">24. Known limitations and issues</a>
<ul class="sectlevel2">
<li><a href="#_code_with_macros_that_dont_preserve_meta">24.1. Code with macros that don&#8217;t preserve meta</a></li>
<li><a href="#_locals_pane_and_mutable_values">24.2. Locals pane and mutable values</a></li>
<li><a href="#_closed_over_bindings_arent_displayed_in_locals">24.3. Closed over bindings aren&#8217;t displayed in Locals</a></li>
<li><a href="#_dont_instrument_clojure_core_or_flowstorm_itself">24.4. Don&#8217;t instrument clojure.core or FlowStorm itself</a></li>
<li><a href="#_if_test_expressions_tracing_with_intrinsics">24.5. IF test expressions tracing with intrinsics</a></li>
<li><a href="#_loading_an_entire_file_while_recording_records_some_weird_code">24.6. Loading an entire file while recording records some weird code</a></li>
<li><a href="#_macro_calls_tracing_code_you_dont_see_on_your_code">24.7. Macro calls tracing code you don&#8217;t see on your code</a></li>
</ul>
</li>
<li><a href="#_troubleshooting">25. Troubleshooting</a>
<ul class="sectlevel2">
<li><a href="#_the_outputs_panel_doesnt_work">25.1. The outputs panel doesn&#8217;t work</a></li>
<li><a href="#_run_with_jdk_11">25.2. Run with JDK 11</a></li>
</ul>
</li>
<li><a href="#_internals_diagrams_and_documentation">26. Internals, diagrams and documentation</a></li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p><em>FlowStorm</em> is a tracing debugger for Clojure and ClojureScript.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/intro_screenshot.png" alt="intro screenshot">
</div>
</div>
<div class="paragraph">
<p>It can instrument any Clojure code and provides many tools to explore and analyze your programs executions.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_quick_start"><a class="anchor" href="#_quick_start"></a><a class="link" href="#_quick_start">1. Quick start</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Before you start check <em>FlowStorm</em> minimum requirements.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<div class="title">Important</div>
</td>
<td class="content">
<div class="title">Minimum requirements</div>
<div class="ulist">
<ul>
<li>
<p>jdk &gt;= 17 (if you still need to run it with jdk11 take a look at <a href="#_run_with_jdk_11">here</a>)</p>
</li>
<li>
<p>Clojure &gt;= 1.10.0</p>
</li>
</ul>
</div>
</td>
</tr>
</table>
</div>
<div class="sect2">
<h3 id="_clojure"><a class="anchor" href="#_clojure"></a><a class="link" href="#_clojure">1.1. Clojure</a></h3>
<div class="paragraph">
<p>There are two ways of using <em>FlowStorm</em> for Clojure :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>With <a href="#_clojurestorm">ClojureStorm</a> (recommended) : Swap your Clojure compiler at dev time by ClojureStorm and get everything instrumented automatically</p>
</li>
<li>
<p><a href="#_vanilla_flowstorm">Vanilla FlowStorm</a> : Just add FlowStorm to your dev classpath and instrument by tagging and re-evaluating forms</p>
</li>
</ul>
</div>
<div class="sect3">
<h4 id="_clojurestorm"><a class="anchor" href="#_clojurestorm"></a><a class="link" href="#_clojurestorm">1.1.1. ClojureStorm</a></h4>
<div class="paragraph">
<p>This is the newest and simplest way of using <em>FlowStorm</em>. It requires you to swap your official Clojure compiler by <em>ClojureStorm</em> only at dev time.</p>
</div>
<div class="paragraph">
<p>Swapping compilers sounds like a lot, but don&#8217;t worry, <em>ClojureStorm</em> is just a patch applied over the official compiler with some
extra stuff for automatic instrumentation. You shouldn&#8217;t encounter any differences, it is only for dev, and you can swap it back
and forth by starting your repl with a different alias or lein profile.</p>
</div>
<div class="paragraph">
<p>The easiest way to run and learn <em>FlowStorm</em> with <em>ClojureStorm</em> is by running the repl tutorial.</p>
</div>
<div class="sect4">
<h5 id="_try_it_with_no_project_and_no_config"><a class="anchor" href="#_try_it_with_no_project_and_no_config"></a><a class="link" href="#_try_it_with_no_project_and_no_config">Try it with no project and no config</a></h5>
<div class="paragraph">
<p>You can start a repl with FlowStorm with a single command like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="bash"><span class="p">;;</span> on Linux and OSX
clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {} :aliases {:dev {:classpath-overrides {org.clojure/clojure nil} :extra-deps {com.github.flow-storm/clojure {:mvn/version "1.12.3-4"} com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}}}'</span> <span class="nt">-A</span>:dev

<span class="p">;;</span> on Windows
clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {} :aliases {:dev {:classpath-overrides {org.clojure/clojure nil} :extra-deps {com.github.flow-storm/clojure {:mvn/version """1.12.3-4"""} com.github.flow-storm/flow-storm-dbg {:mvn/version """4.5.9"""}}}}}'</span> <span class="nt">-A</span>:dev</code></pre>
</div>
</div>
<div class="paragraph">
<p>Pasting that command on your terminal will bring up a repl with <em>FlowStorm</em> and the compiler swapped by <em>ClojureStorm</em>. When the repl comes up
evaluate the <code>:dbg</code> keyword to bring up the UI and then click on  <code>Help&#8594;Tutorial</code> on the menu for a tour of the basics.</p>
</div>
<div class="paragraph">
<p>After the tutorial you may want to use it on your projects. You use it by adding a deps.edn alias or  lein profile.</p>
</div>
<div class="paragraph">
<p>The simplest way is to setup it globally, so that is what we are going to do next. You can also add it only
to specific projects if they require special configurations.</p>
</div>
</div>
<div class="sect4">
<h5 id="_global_setup_as_deps_edn_aliases"><a class="anchor" href="#_global_setup_as_deps_edn_aliases"></a><a class="link" href="#_global_setup_as_deps_edn_aliases">Global setup as deps.edn aliases</a></h5>
<div class="paragraph">
<p>You can setup your global <code>~/.clojure/deps.edn</code> (on linux and macOS) or <code>%USERPROFILE%\.clojure\deps.edn</code> (on windows) like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">{</span><span class="n">...</span><span class="w">
 </span><span class="no">:aliases</span><span class="w">
 </span><span class="p">{</span><span class="no">:1.12-storm</span><span class="w"> </span><span class="p">{</span><span class="no">:classpath-overrides</span><span class="w"> </span><span class="p">{</span><span class="n">org.clojure/clojure</span><span class="w"> </span><span class="n">nil</span><span class="p">}</span><span class="w">
               </span><span class="no">:extra-deps</span><span class="w"> </span><span class="p">{</span><span class="n">com.github.flow-storm/clojure</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"1.12.3-4"</span><span class="p">}</span><span class="w">
                            </span><span class="n">com.github.flow-storm/flow-storm-dbg</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">}}}</span><span class="w">

  </span><span class="c1">;; Optional plugins you find yourself using regularly</span><span class="w">
  </span><span class="no">:fs-web-plugin</span><span class="w"> </span><span class="p">{</span><span class="no">:extra-deps</span><span class="w"> </span><span class="p">{</span><span class="n">com.github.flow-storm/flow-storm-web-plugin</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"1.0.0-beta"</span><span class="p">}}</span><span class="w">
                  </span><span class="no">:jvm-opts</span><span class="w"> </span><span class="p">[</span><span class="s">"-Dclojure.storm.instrumentOnlyPrefixes.webPlugin=org.httpkit.server,ring.adapter.jetty,next.jdbc.result-set"</span><span class="w">
                             </span><span class="s">"-Dflowstorm.plugins.namespaces.webPlugin=flow-storm.plugins.web.all"</span><span class="p">]}</span><span class="w">

  </span><span class="n">...</span><span class="p">}}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then you can start your repls with the <code>:1.12-storm</code> alias (like <code>clj -A:1.12-storm</code>). When the repl comes up evaluate the <code>:dbg</code> keyword to bring up the UI,
then click on  <code>Help&#8594;Tutorial</code> on the menu for a tour of the basics.</p>
</div>
</div>
<div class="sect4">
<h5 id="_global_setup_as_leiningen_profiles"><a class="anchor" href="#_global_setup_as_leiningen_profiles"></a><a class="link" href="#_global_setup_as_leiningen_profiles">Global setup as leiningen profiles</a></h5>
<div class="paragraph">
<p>You can setup your global <code>~/.lein/profiles.clj</code> (on linux and macOS) or <code>%USERPROFILE%\.lein\profiles.clj</code> (on windows) like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">{</span><span class="no">:1.12-storm</span><span class="w">
 </span><span class="p">{</span><span class="no">:dependencies</span><span class="w"> </span><span class="p">[[</span><span class="n">com.github.flow-storm/clojure</span><span class="w"> </span><span class="s">"1.12.3-4"</span><span class="p">]</span><span class="w">
                 </span><span class="p">[</span><span class="n">com.github.flow-storm/flow-storm-dbg</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">]]</span><span class="w">
  </span><span class="no">:exclusions</span><span class="w"> </span><span class="p">[</span><span class="n">org.clojure/clojure</span><span class="p">]}</span><span class="w">

 </span><span class="c1">;; Optional plugins you find yourself using regularly</span><span class="w">
 </span><span class="no">:fs-web-plugin</span><span class="w">
 </span><span class="p">{</span><span class="no">:dependencies</span><span class="w"> </span><span class="p">[[</span><span class="n">com.github.flow-storm/flow-storm-web-plugin</span><span class="w"> </span><span class="s">"1.0.0-beta"</span><span class="p">]]</span><span class="w">
  </span><span class="no">:jvm-opts</span><span class="w"> </span><span class="p">[</span><span class="s">"-Dclojure.storm.instrumentOnlyPrefixes.webPlugin=org.httpkit.server,ring.adapter.jetty,next.jdbc.result-set"</span><span class="w">
             </span><span class="s">"-Dflowstorm.plugins.namespaces.webPlugin=flow-storm.plugins.web.all"</span><span class="p">]}</span><span class="w">
</span><span class="n">...</span><span class="p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then you can start your project repls with <code>+1.12-storm</code> profile (like <code>lein with-profile +1.12-storm repl</code>). When the repl comes up evaluate the <code>:dbg</code> keyword to bring up the UI,
then click on  <code>Help&#8594;Tutorial</code> on the menu for a tour of the basics.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Running lein repl without a project</div>
<div class="paragraph">
<p>For some reason if you run <code>lein with-profile +1.12-storm repl</code> outside of a project it will not run with the profile
activated correctly.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="_per_project_setup_with_deps_edn"><a class="anchor" href="#_per_project_setup_with_deps_edn"></a><a class="link" href="#_per_project_setup_with_deps_edn">Per project setup with deps.edn</a></h5>
<div class="paragraph">
<p>If your project is using deps.edn, you can add an alias that looks like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">{</span><span class="n">...</span><span class="w">
 </span><span class="no">:aliases</span><span class="w"> </span><span class="p">{</span><span class="no">:1.12-storm</span><span class="w">
           </span><span class="p">{</span><span class="c1">;; for disabling the official compiler</span><span class="w">
            </span><span class="no">:classpath-overrides</span><span class="w"> </span><span class="p">{</span><span class="n">org.clojure/clojure</span><span class="w"> </span><span class="n">nil</span><span class="p">}</span><span class="w">
            </span><span class="no">:extra-deps</span><span class="w"> </span><span class="p">{</span><span class="n">com.github.flow-storm/clojure</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"1.12.3-4"</span><span class="p">}</span><span class="w">
                         </span><span class="n">com.github.flow-storm/flow-storm-dbg</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">}}}}}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Once you have setup your deps.edn, start your repl with the <code>:1.12-storm</code> alias and run the debugger by evaluating
the <code>:dbg</code> keyworkd on your repl (this means just type <code>:dbg</code> and hit return).</p>
</div>
<div class="paragraph">
<p>If it is your first time using FlowStorm, when the UI comes up click on <code>Help&#8594;Tutorial</code> on the menu for a tour of the basics.</p>
</div>
<div class="paragraph">
<p>If you need more fine control over instrumentation see <a href="#_controlling_instrumentation">controlling instrumentation</a>.</p>
</div>
</div>
<div class="sect4">
<h5 id="_setup_with_leiningen"><a class="anchor" href="#_setup_with_leiningen"></a><a class="link" href="#_setup_with_leiningen">Setup with leiningen</a></h5>
<div class="paragraph">
<p>If your project uses lein, you can add a profile that looks like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">(</span><span class="nf">defproject</span><span class="w"> </span><span class="n">my.project</span><span class="w"> </span><span class="s">"1.0.0"</span><span class="w">
  </span><span class="no">:profiles</span><span class="w"> </span><span class="p">{</span><span class="no">:1.12-storm</span><span class="w">
             </span><span class="p">{</span><span class="no">:dependencies</span><span class="w"> </span><span class="p">[[</span><span class="n">com.github.flow-storm/clojure</span><span class="w"> </span><span class="s">"1.12.3-4"</span><span class="p">]</span><span class="w">
                             </span><span class="p">[</span><span class="n">com.github.flow-storm/flow-storm-dbg</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">]]</span><span class="w">
              </span><span class="no">:exclusions</span><span class="w"> </span><span class="p">[</span><span class="n">org.clojure/clojure</span><span class="p">]}}</span><span class="w">
  </span><span class="n">...</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Once you have setup your lein profile globally or per project, start your repl with the <code>1.12-storm</code> profile and run the debugger by evaluating
the <code>:dbg</code> keyworkd on your repl (this means just type <code>:dbg</code> and hit return).</p>
</div>
<div class="paragraph">
<p>Make sure you activate the profile with <code>lein with-profile +1.12-storm repl</code>.</p>
</div>
<div class="paragraph">
<p>If it is your first time using FlowStorm, when the UI comes up click on <code>Help&#8594;Tutorial</code> on the menu for a tour of the basics.</p>
</div>
<div class="paragraph">
<p>If you need more fine control over instrumentation see <a href="#_controlling_instrumentation">controlling instrumentation</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">lein dependencies</div>
<div class="paragraph">
<p>If you are using lein &lt; 2.11.0 make sure your global :dependencies don&#8217;t include the official org.clojure/clojure dependency.
Moving to lein latest version should work ok even if your global :dependencies contains the Clojure dep.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_vanilla_flowstorm"><a class="anchor" href="#_vanilla_flowstorm"></a><a class="link" href="#_vanilla_flowstorm">1.1.2. Vanilla FlowStorm</a></h4>
<div class="paragraph">
<p>If you use the <a href="https://clojure.org/guides/deps_and_cli">clojure cli</a> you can start a repl with the <em>FlowStorm</em> dependency loaded like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash"><span class="p">;;</span> on Linux and OSX
clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span>

<span class="p">;;</span> on Windows
clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version """4.5.9"""}}}'</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>If you are a <a href="https://leiningen.org/">lein</a> user add the dependency to your project.clj <code>:dependencies</code> and run <code>lein repl</code>.</p>
</div>
<div class="paragraph">
<p>Then require the api namespace and start the debugger :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">require</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">flow-storm.api</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">fs-api</span><span class="p">])</span><span class="w"> </span><span class="c1">;; the only namespace you need to require</span><span class="w">

</span><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">fs-api/local-connect</span><span class="p">)</span><span class="w"> </span><span class="c1">;; will run the debugger GUI and get everything ready</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>You should now see a empty debugger window. Click on the recording button to leave the debugger in
recording mode and the let&#8217;s debug something:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="n">user&gt;</span><span class="w"> </span><span class="o">#</span><span class="n">rtrace</span><span class="w"> </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">inc</span><span class="w"> </span><span class="p">(</span><span class="nb">range</span><span class="w"> </span><span class="mi">10</span><span class="p">)))</span><span class="w"> </span><span class="c1">;; #rtrace will instrument and run some code</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>After running it, you should get the return value of the expression (as if #rtrace wasn&#8217;t there),
but now you will also have the debugger UI showing your recordings.</p>
</div>
<div class="paragraph">
<p>From here you probably want to check out the <a href="#_flows_tool">Flows tool</a> which contains a lot of information
about exploring your recordings.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_clojurescript"><a class="anchor" href="#_clojurescript"></a><a class="link" href="#_clojurescript">1.2. ClojureScript</a></h3>
<div class="paragraph">
<p>Debugging ClojureScript is a case of remote debugging in <em>FlowStorm</em>. This means the debugger
will run in a separate process and connect to the debuggee (your browser or nodejs runtime) via a websocket and optionally
an nrepl server.</p>
</div>
<div class="paragraph">
<p>There are two ways of using <em>FlowStorm</em> with ClojureScript :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>With <a href="#_clojurescriptstorm_with_shadow_cljs">ClojureScriptStorm</a> (recommended) : Swap your ClojureScript compiler by ClojureScriptStorm at dev and get everything instrumented automatically</p>
</li>
<li>
<p><a href="#_clojurescript_vanilla_flowstorm">Vanilla FlowStorm</a> : Just add FlowStorm to your dev classpath and instrument by tagging and re-evaluating forms</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><em>ClojureScriptStorm</em> is a fork of the official ClojureScript compiler that adds automatic instrumentation so you don&#8217;t need to think about it (you can still disable it when you don&#8217;t need it).</p>
</div>
<div class="paragraph">
<p>You use it by swapping the official ClojureScript compiler by <em>ClojureScriptStorm</em> at dev time, using dev aliases or profiles.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Repl connection</div>
<div class="paragraph">
<p>For enabling every debugger feature, <em>FlowStorm</em> needs to connect to a cljs repl.
Currently only shadow-cljs repl over nrepl is supported.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_clojurescriptstorm_with_shadow_cljs"><a class="anchor" href="#_clojurescriptstorm_with_shadow_cljs"></a><a class="link" href="#_clojurescriptstorm_with_shadow_cljs">1.2.1. ClojureScriptStorm with shadow-cljs</a></h4>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<div class="title">Important</div>
</td>
<td class="content">
<div class="title">Minimum requirements</div>
<div class="ulist">
<ul>
<li>
<p>For ClojureScript 1.11.* shadow-cljs &gt;= 2.25.4,  For ClojureScript 1.12.* shadow-cljs &gt;= 3.1.1</p>
</li>
<li>
<p>FlowStorm &gt;= 3.7.4</p>
</li>
</ul>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For setting up <em>FlowStorm</em> with shadow-cljs you need to modify two files, your <code>shadow-cljs.edn</code> and your <code>deps.edn</code>.
This is setup once and forget, so once you have configured <em>FlowStorm</em> you can do everything from the UI, without
any other sources modifications.</p>
</div>
<div class="paragraph">
<p>If you want a shadow-cljs template to play with, take a look at <a href="https://github.com/jpmonettas/shadow-flow-storm-basic/">this repo</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">shadow-cljs</div>
<div class="paragraph">
<p>Currently you can only use <em>ClojureScriptStorm</em> with shadow-cljs if you are resolving your
dependencies with deps.edn. This means having <code>:deps true</code> or similar in your shadow-cljs.edn.
If you have your dependencies directly in your shadow-cljs.edn you will have to use <a href="#_clojurescript_vanilla_flowstorm">Vanilla FlowStorm</a>
for now.
This is because there is currently no way to swap the ClojureScript compiler in shadow-cljs.edn.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>First, make your shadow-cljs.edn looks something like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">{</span><span class="no">:deps</span><span class="w"> </span><span class="p">{</span><span class="no">:aliases</span><span class="w"> </span><span class="p">[</span><span class="no">:1.12-cljs-storm</span><span class="p">]}</span><span class="w">
 </span><span class="no">:nrepl</span><span class="w"> </span><span class="p">{</span><span class="no">:port</span><span class="w"> </span><span class="mi">9000</span><span class="p">}</span><span class="w">
 </span><span class="n">...</span><span class="w">
 </span><span class="no">:builds</span><span class="w">
 </span><span class="p">{</span><span class="no">:my-app</span><span class="w"> </span><span class="p">{</span><span class="n">...</span><span class="w">
           </span><span class="no">:devtools</span><span class="w"> </span><span class="p">{</span><span class="no">:preloads</span><span class="w"> </span><span class="p">[</span><span class="n">flow-storm.storm-preload</span><span class="p">]</span><span class="w">
                      </span><span class="no">:http-port</span><span class="w"> </span><span class="mi">8021</span><span class="p">}}}}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>So, the important parts are: you need to tell shadow to apply your deps.edn :1.12-cljs-storm alias, set up a nrepl port,
and also add <code>flow-storm.storm-preload</code> to your preloads. If you have other preloads make sure <code>flow-storm.storm-preload</code>
is the first one.</p>
</div>
<div class="paragraph">
<p>Then, modify your <code>deps.edn</code> dev profile to look like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">{</span><span class="n">...</span><span class="w">
 </span><span class="no">:aliases</span><span class="w">
 </span><span class="c1">;; this alias can be defined globally in your ~/.clojure/deps.edn so you don't have to modify this file in your project</span><span class="w">
 </span><span class="p">{</span><span class="no">:1.12-cljs-storm</span><span class="w">
    </span><span class="p">{</span><span class="no">:classpath-overrides</span><span class="w"> </span><span class="p">{</span><span class="n">org.clojure/clojurescript</span><span class="w"> </span><span class="n">nil</span><span class="p">}</span><span class="w"> </span><span class="c1">;; disable the official compiler</span><span class="w">
     </span><span class="no">:extra-deps</span><span class="w"> </span><span class="p">{</span><span class="n">thheller/shadow-cljs</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"3.3.2"</span><span class="w">
                                        </span><span class="no">:exclusions</span><span class="w"> </span><span class="p">[</span><span class="n">org.clojure/clojurescript</span><span class="p">]}</span><span class="w">
                  </span><span class="c1">;; bring ClojureScriptStorm</span><span class="w">
                  </span><span class="n">com.github.flow-storm/clojurescript</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"1.12.116-2"</span><span class="p">}</span><span class="w">
                  </span><span class="c1">;; add FlowStorm runtime dep</span><span class="w">
                  </span><span class="n">com.github.flow-storm/flow-storm-inst</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">}}}}}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>There are lots of things going on there, but the main ones are: disabling the official compiler, adding
<em>ClojureScriptStorm</em> and <em>FlowStorm</em> dependencies, and then configuring what you want <em>ClojureScriptStorm</em> to automatically
instrument.</p>
</div>
<div class="paragraph">
<p>By default the JVM property <code>cljs.storm.instrumentAutoPrefixes</code> is true so all your project top level namespaces
will be instrumented automatically.</p>
</div>
<div class="paragraph">
<p>If you need to set that property to false it is important to configure what namespaces you want to instrument,
and you do this by setting the <code>cljs.storm.instrumentOnlyPrefixes</code> jvm property.</p>
</div>
<div class="paragraph">
<p>This is a comma separated list of namespaces prefixes, you normally want your app namespaces plus some libraries, like :
<code>cljs.storm.instrumentOnlyPrefixes=org.my-app,org.my-lib,hiccup</code></p>
</div>
<div class="paragraph">
<p>And this is it. Once you have it configured, run your shadow watch as you normally do, load your app on the browser (or nodejs).</p>
</div>
<div class="paragraph">
<p>Whenever your need the debugger, on a terminal run the ui with your shadow-cljs.edn data :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port 9000 :repl-type :shadow :build-id :my-app</code></pre>
</div>
</div>
<div class="paragraph">
<p>and then reload you page so it connects to it.</p>
</div>
<div class="paragraph">
<p>Since we started the app with <code>flowstorm.startRecording=false</code> you will have to click on the record button once to start recording.
Whenever recording is enable and something executes under an instrumented namespace you should see the recordings appear in the debugger
under the main thread.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">recording expressions typed on the repl</div>
<div class="paragraph">
<p>If you type at the repl something like <code>(defn foo [a b] (+ a b))</code> under an instrumented ns, the <code>foo</code> function will get instrumented
automatically and you will able to explore the recordings after the function is called.
On the other side, typing a simple expression like <code>(+ 1 2)</code> will not show anything, this is currently a limitation but you can
still make that work by wrapping the expression on a fn and immediately calling it, like <code>fn [] (+ 1 2)</code></p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_clojurescriptstorm_with_cljs_main"><a class="anchor" href="#_clojurescriptstorm_with_cljs_main"></a><a class="link" href="#_clojurescriptstorm_with_cljs_main">1.2.2. ClojureScriptStorm with cljs.main</a></h4>
<div class="paragraph">
<p>You can use <em>FlowStorm</em> and <em>ClojureScriptStorm</em> with cljs.main.</p>
</div>
<div class="paragraph">
<p>To compile instrumented files :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="bash">clj <span class="nt">-J-Dcljs</span>.storm.instrumentOnlyPrefixes<span class="o">=</span>org.foo <span class="nt">-J-Dcljs</span>.storm.instrumentEnable<span class="o">=</span><span class="nb">true</span> <span class="nt">-Sdeps</span> <span class="s1">'{:paths ["src"] :deps {com.github.flow-storm/clojurescript {:mvn/version "1.11.132-9"} com.github.flow-storm/flow-storm-inst {:mvn/version "4.5.9"}}}'</span> <span class="nt">-M</span> <span class="nt">-m</span> cljs.main <span class="nt">-co</span> <span class="s1">'{:preloads [flow-storm.storm-preload] :main org.foo.core}'</span> <span class="nt">--compile</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>To run a repl that instrument everything under org.foo :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="bash">clj <span class="nt">-J-Dcljs</span>.storm.instrumentOnlyPrefixes<span class="o">=</span>org.foo <span class="nt">-J-Dcljs</span>.storm.instrumentEnable<span class="o">=</span><span class="nb">true</span> <span class="nt">-Sdeps</span> <span class="s1">'{:paths ["src"] :deps {com.github.flow-storm/clojurescript {:mvn/version "1.11.132-9"} com.github.flow-storm/flow-storm-inst {:mvn/version "4.5.9"}}}'</span> <span class="nt">-M</span> <span class="nt">-m</span> cljs.main <span class="nt">-co</span> <span class="s1">'{:preloads [flow-storm.storm-preload] :main org.foo.core}'</span> <span class="nt">--repl</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then run the <em>FlowStorm</em> UI :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="bash">clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger</code></pre>
</div>
</div>
<div class="paragraph">
<p>And now refresh your browser page so your browser app connects to the UI.</p>
</div>
</div>
<div class="sect3">
<h4 id="_clojurescript_vanilla_flowstorm"><a class="anchor" href="#_clojurescript_vanilla_flowstorm"></a><a class="link" href="#_clojurescript_vanilla_flowstorm">1.2.3. ClojureScript vanilla FlowStorm</a></h4>
<div class="paragraph">
<p>Let&#8217;s say you are using <a href="https://github.com/thheller/shadow-cljs">shadow-cljs</a> to start a ClojureScript repl.</p>
</div>
<div class="paragraph">
<p>First you need to add <em>FlowStorm</em> dependency to your project dependencies, like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="n">$</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="n">shadow-cljs.edn</span><span class="w">

</span><span class="p">{</span><span class="n">...</span><span class="w">
 </span><span class="no">:dependencies</span><span class="w"> </span><span class="p">[</span><span class="n">...</span><span class="w"> </span><span class="p">[</span><span class="n">com.github.flow-storm/flow-storm-inst</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">]]</span><span class="w">

 </span><span class="c1">;; the next two lines aren't needed but pretty convenient</span><span class="w">
 </span><span class="no">:nrepl</span><span class="w"> </span><span class="p">{</span><span class="no">:port</span><span class="w"> </span><span class="mi">9000</span><span class="p">}</span><span class="w">
 </span><span class="no">:my-build-id</span><span class="w"> </span><span class="p">{</span><span class="no">:devtools</span><span class="w"> </span><span class="p">{</span><span class="no">:preloads</span><span class="w"> </span><span class="p">[</span><span class="n">flow-storm.preload</span><span class="p">]}}</span><span class="w">
 </span><span class="n">...</span><span class="p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then let&#8217;s say you start your repl like :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">npx shadow-cljs watch :my-build-id

shadow-cljs - config: /home/jmonetta/demo/shadow-cljs.edn
shadow-cljs - server version: 2.19.0 running at http://localhost:9630
shadow-cljs - nREPL server started on port 9000
shadow-cljs - watching build :my-build-id
<span class="o">[</span>:my-build-id] Configuring build.
<span class="o">[</span>:my-build-id] Compiling ...
<span class="o">[</span>:my-build-id] Build completed. <span class="o">(</span>127 files, 0 compiled, 0 warnings, 6.19s<span class="o">)</span>

cljs.user<span class="o">=&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>As you can see from the output log shadow-cljs started a nrepl server on port 9000, this is the port <em>FlowStorm</em> needs to connect to,
so to start the debugger and connect to it you run :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash"><span class="p">;;</span> on linux and mac-os
clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port 9000 :repl-type :shadow :build-id :my-build-id

<span class="p">;;</span> on windows
clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version """4.5.9"""}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port 9000 :repl-type :shadow :build-id :my-build-id</code></pre>
</div>
</div>
<div class="paragraph">
<p>And that is all you need, the debugger GUI will pop up and everything will be ready.</p>
</div>
<div class="paragraph">
<p>Try tracing some code from the repl :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="n">cljs.user&gt;</span><span class="w"> </span><span class="o">#</span><span class="n">rtrace</span><span class="w"> </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">inc</span><span class="w"> </span><span class="p">(</span><span class="nb">range</span><span class="w"> </span><span class="mi">10</span><span class="p">)))</span><span class="w"> </span><span class="c1">;; #rtrace will instrument and run some code</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>After running it, you should get the return value of the expression (as if #rtrace wasn&#8217;t there).</p>
</div>
<div class="paragraph">
<p>The debugger thread list (the one on the left) shows all the threads it has recordings for. Because we are
in javascript land there will always be just one thread, called <code>main</code>.
Double clicking it should open the "thread exploring tools" for that thread in a new tab.</p>
</div>
<div class="paragraph">
<p>This guide will cover all the tools in more detail but if you are interested in code stepping for example you will find
it in the <code>code stepping tool</code> at the bottom left corner of the thread tab, the one that has the <code>()</code> icon.</p>
</div>
<div class="paragraph">
<p>Click on it and use the stepping controls to step over the code.</p>
</div>
<div class="paragraph">
<p>Now that everything seems to be working move on and explore the many features <em>FlowStorm</em> provides. There are many ways of instrumenting
your code, and many ways to explore its executions.</p>
</div>
<div class="paragraph">
<p>If you are not using a repl or the repl you are using isn&#8217;t supported by <em>FlowStorm</em> yet you can still use the debugger
but not all features will be supported (mainly the browser features).</p>
</div>
<div class="paragraph">
<p>For this you can start the debugger like before but without any parameters, like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger</code></pre>
</div>
</div>
<div class="paragraph">
<p>And then go to your app code and call <code>(flow-storm.runtime.debuggers-api/remote-connect)</code> maybe on your main, so every time your program starts
will automatically connect to the repl.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">ClojureScript environments</div>
<div class="paragraph">
<p><em>FlowStorm</em> is supported for ClojureScript in :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Browsers</p>
</li>
<li>
<p>NodeJS</p>
</li>
<li>
<p>React native</p>
</li>
</ul>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">NodeJs and react-native</div>
<div class="paragraph">
<p>On NodeJs and react-native you need to install the <code>websocket</code> library.
Do this by running <code>npm install websocket --save</code></p>
</div>
<div class="paragraph">
<p>For react-native if your app is running inside a cellphone you will have to also provide the <code>:debugger-host</code> key
to <code>flow-storm.debugger.main/start-debugger</code> with your box ip address, unless you are using adb reverse with your ports for
which you will have to <code>adb reverse tcp:7722 tcp:7722</code> (the debugger websocket port)</p>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">App initialization debugging</div>
<div class="paragraph">
<p>If you need to debug some app initialization, for adding <code>#trace</code> tags before the debugger is connected you
will have to require flow-storm.api yourself, probably in your main. All the tracing will be replayed to the debugger
once it is connected.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Here is a repo you can use if you want to try <em>FlowStorm</em> with shadow-cljs <a href="https://github.com/flow-storm/shadow-flow-storm-basic" class="bare">https://github.com/flow-storm/shadow-flow-storm-basic</a></p>
</div>
</div>
<div class="sect3">
<h4 id="_multiple_clojurescript_builds"><a class="anchor" href="#_multiple_clojurescript_builds"></a><a class="link" href="#_multiple_clojurescript_builds">1.2.4. Multiple ClojureScript builds</a></h4>
<div class="paragraph">
<p>You can setup FlowStorm to debug multiple ClojureScript builds. This can be useful when your application is made up of multiple parts,
like when you have web workers.</p>
</div>
<div class="paragraph">
<p>Debugging multiple builds require multiple debugger instances, one per build.</p>
</div>
<div class="paragraph">
<p>The FlowStorm UI will start a websocket server, by default on 7722, so if you want to run multiple instances of it, you need
to run each instance under a different port. You can do this by providing a <code>:ws-port</code> to the startup command.</p>
</div>
<div class="paragraph">
<p>So let&#8217;s say you want to run two debuggers, one for your page and one for a webworker, your can run them like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash"><span class="c"># on one terminal start your app debugger instance</span>
clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port 9000 :repl-type :shadow :build-id :my-app :ws-port 7722

<span class="c"># on a second terminal start your webworker debugger instance</span>
clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port 9000 :repl-type :shadow :build-id :my-web-worker :ws-port 7733</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now you also need to configure your builds to tell them what port they should connect to.
You do this by writing different preloads for each of your builds, and then using them instead of your <code>flow-storm.storm-preload</code>, like:</p>
</div>
<div class="paragraph">
<p><code>my_app.main_storm_preload.cljs</code></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">(</span><span class="nf">ns</span><span class="w"> </span><span class="n">my-app.main-storm-preload</span><span class="w">
  </span><span class="p">(</span><span class="no">:require</span><span class="w"> </span><span class="p">[</span><span class="n">cljs.storm.tracer</span><span class="p">]</span><span class="w">
            </span><span class="p">[</span><span class="n">flow-storm.tracer</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">tracer</span><span class="p">]</span><span class="w">
            </span><span class="p">[</span><span class="n">flow-storm.runtime.debuggers-api</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">dbg-api</span><span class="p">]))</span><span class="w">

</span><span class="p">(</span><span class="nf">dbg-api/start-runtime</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">tracer/hook-clojurescript-storm</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">dbg-api/remote-connect</span><span class="w"> </span><span class="p">{</span><span class="no">:debugger-host</span><span class="w"> </span><span class="s">"localhost"</span><span class="w"> </span><span class="no">:debugger-ws-port</span><span class="w"> </span><span class="mi">7722</span><span class="p">})</span></code></pre>
</div>
</div>
<div class="paragraph">
<p><code>my_app.webworker_storm_preload.cljs</code></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">(</span><span class="nf">ns</span><span class="w"> </span><span class="n">my-app.webworker-storm-preload</span><span class="w">
  </span><span class="p">(</span><span class="no">:require</span><span class="w"> </span><span class="p">[</span><span class="n">cljs.storm.tracer</span><span class="p">]</span><span class="w">
            </span><span class="p">[</span><span class="n">flow-storm.tracer</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">tracer</span><span class="p">]</span><span class="w">
            </span><span class="p">[</span><span class="n">flow-storm.runtime.debuggers-api</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">dbg-api</span><span class="p">]))</span><span class="w">

</span><span class="p">(</span><span class="nf">dbg-api/start-runtime</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">tracer/hook-clojurescript-storm</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">dbg-api/remote-connect</span><span class="w"> </span><span class="p">{</span><span class="no">:debugger-host</span><span class="w"> </span><span class="s">"localhost"</span><span class="w"> </span><span class="no">:debugger-ws-port</span><span class="w"> </span><span class="mi">7733</span><span class="p">})</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>They are the same as <code>flow-storm.storm-preload</code> just with different port numbers.</p>
</div>
<div class="paragraph">
<p>Now you can configure your shadow-cljs.edn like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">{</span><span class="n">...</span><span class="w">
 </span><span class="no">:builds</span><span class="w">
 </span><span class="p">{</span><span class="no">:app</span><span class="w">
  </span><span class="p">{</span><span class="no">:target</span><span class="w"> </span><span class="no">:browser</span><span class="w">
   </span><span class="n">...</span><span class="w">
   </span><span class="no">:modules</span><span class="w">
   </span><span class="p">{</span><span class="no">:my-app</span><span class="w"> </span><span class="p">{</span><span class="no">:init-fn</span><span class="w"> </span><span class="n">my.app/init</span><span class="w">
           </span><span class="no">:preloads</span><span class="w"> </span><span class="p">[</span><span class="n">my-app.main-storm-preload</span><span class="p">]}</span><span class="w">
    </span><span class="no">:my-webworker</span><span class="w"> </span><span class="p">{</span><span class="no">:init-fn</span><span class="w"> </span><span class="n">my.app.worker/init</span><span class="w">
                   </span><span class="no">:preloads</span><span class="w"> </span><span class="p">[</span><span class="n">my-app.webworker-storm-preload</span><span class="p">]</span><span class="w">
                   </span><span class="no">:web-worker</span><span class="w"> </span><span class="n">true</span><span class="p">}}}}}</span></code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Multiple debuggers tips</div>
<div class="paragraph">
<p>You can change the theme or customize the styles of different instances to make it easier to
know which debugger instance is connected to which application.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_babashka"><a class="anchor" href="#_babashka"></a><a class="link" href="#_babashka">1.3. Babashka</a></h3>
<div class="paragraph">
<p>You can debug your babashka scripts with FlowStorm using the JVM. The process is quite simple.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s say we want to debug this example script <a href="https://raw.githubusercontent.com/babashka/babashka/master/examples/htmx_todoapp.clj" class="bare">https://raw.githubusercontent.com/babashka/babashka/master/examples/htmx_todoapp.clj</a>
which runs a webserver with a basic todo app.</p>
</div>
<div class="paragraph">
<p>First we need to generate a deps.edn by running <code>bb print-deps &gt; deps.edn</code></p>
</div>
<div class="paragraph">
<p>Then modify the resulting deps.edn to add the FlowStorm alias like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">{</span><span class="n">...</span><span class="w">
 </span><span class="no">:aliases</span><span class="w"> </span><span class="p">{</span><span class="no">:dev</span><span class="w"> </span><span class="p">{</span><span class="no">:classpath-overrides</span><span class="w"> </span><span class="p">{</span><span class="n">org.clojure/clojure</span><span class="w"> </span><span class="n">nil</span><span class="p">}</span><span class="w"> </span><span class="c1">;; for disabling the official compiler</span><span class="w">
                 </span><span class="no">:extra-deps</span><span class="w"> </span><span class="p">{</span><span class="n">com.github.flow-storm/clojure</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"1.12.3-4"</span><span class="p">}</span><span class="w">
                              </span><span class="n">com.github.flow-storm/flow-storm-dbg</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">}}</span><span class="w">
                 </span><span class="no">:jvm-opts</span><span class="w"> </span><span class="p">[</span><span class="s">"-Dclojure.storm.instrumentOnlyPrefixes=user"</span><span class="p">]}}}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>With <code>clojure.storm.instrumentOnlyPrefixes=user</code> we are telling ClojureStorm to instrument everything inside
the <code>user</code> namespace since the script doesn&#8217;t contain any namespace declaration.</p>
</div>
<div class="paragraph">
<p>And that is it, you can now start your clojure repl as usual, with <code>clj -A:dev</code> and then eval the <code>:dbg</code> keyword to
start the debugger UI.</p>
</div>
<div class="paragraph">
<p>Then eval the entire file to compile everything. To start the server in this example you will have to remove the wrapping
that is basically only allowing the server to run if we are running from babashka, like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">(</span><span class="nb">when</span><span class="w"> </span><span class="n">true</span><span class="w"> </span><span class="o">#</span><span class="n">_</span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="n">*file*</span><span class="w"> </span><span class="p">(</span><span class="nf">System/getProperty</span><span class="w"> </span><span class="s">"babashka.file"</span><span class="p">))</span><span class="w">
  </span><span class="n">...</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>so we can also start it from Clojure.</p>
</div>
<div class="paragraph">
<p>After the server has started, you can use the app from the browser and everything will get recorded as usual.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_tool_bar"><a class="anchor" href="#_the_tool_bar"></a><a class="link" href="#_the_tool_bar">2. The tool bar</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The toolbar as well as the menu provides quick access to some general commands.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/toolbar.png" alt="toolbar">
</div>
</div>
<div class="paragraph">
<p>From left to right:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Cancel current running task. Whenever you a running a task that can take some time, this button will be red, and you can use it to cancel the task.</p>
</li>
<li>
<p>The <code>Inst enable</code> button allows to enable/disable instrumentation when in a Storm environment. A change on instrumentation will only affect newly compiled code.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_flows_tool"><a class="anchor" href="#_flows_tool"></a><a class="link" href="#_flows_tool">3. Flows tool</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>Flows</code> vertical tab contains a bunch of tools for recording and analyzing your programs executions.</p>
</div>
<div class="paragraph">
<p>First of all, what are Flows?</p>
</div>
<div class="paragraph">
<p>A Flow is an "execution flow" recording unit. The only purpose of a flow is to group recording activity.
This grouping allows us for example to run some code and record it under <code>flow-0</code>, then modify our code, run it again, and
record this second run (or flow) under <code>flow-1</code>. Now we can access both recordings separately.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/recording_controls.png" alt="recording controls">
</div>
</div>
<div class="paragraph">
<p>When you first open FlowStorm UI you will see four things, from left to right :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Clear your recordings if any.</p>
</li>
<li>
<p>Start/Stop recording. You can keep your heap from growing by stopping recording when you don&#8217;t need it.</p>
</li>
<li>
<p>Start/Stop recording the multi-thread timeline. Check out the <a href="#_multi_thread_timeline">multi-thread timeline</a> tool.</p>
</li>
<li>
<p>The <code>Rec on</code> combo-box to select under what flow new recordings are going to be stored.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Whenever there is something recorded for a flow, a new tab with the flow name will appear.</p>
</div>
<div class="paragraph">
<p>Execution inside a flow will be grouped by threads. So the first thing you will see on a flow is a menu of threads
we have recordings for so far. This threads will be referred sometimes as timelines, since they are a sequence of
recorded execution steps.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s say for example we have selected to record under <code>flow-1</code> and run some multi threaded code.</p>
</div>
<div class="paragraph">
<p>We are going to see something like this :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/multi_flows_1.png" alt="multi flows 1">
</div>
</div>
<div class="paragraph">
<p>There is a lot going on in the screenshot above, but the most important are :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>we have configured FlowStorm to record new executions under <code>flow-1</code></p>
</li>
<li>
<p>we have recorded stuff under <code>flow-1</code> and there are also some previous recordings under <code>flow-0</code></p>
</li>
<li>
<p>we are currently looking at <code>flow-1</code>, we have opened to explore the thread with id <code>1</code> called <code>main</code> and we are exploring it in <a href="#_code_stepping">the code stepper</a></p>
</li>
<li>
<p><code>Threads [4]</code> indicates we have recorded activity in 4 threads, which we can access via this menu</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Now for a different example :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/multi_flows_2.png" alt="multi flows 2">
</div>
</div>
<div class="paragraph">
<p>This second image shows us exploring the recordings of a thread with id <code>474</code>, called <code>pool-4-thread-4</code> on <code>flow-0</code>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/flows_toolbar.png" alt="flows toolbar">
</div>
</div>
<div class="paragraph">
<p>The <code>Flows tool</code> also contains a toolbar that contains the Quick jump box.
Use it for quickly opening the first recording of a function in <a href="#_code_stepping">the code stepper</a>.
Will autocomplete the first 25 matches.</p>
</div>
<div class="paragraph">
<p>In the screenshot above we see analyzing the recordings in <a href="#_code_stepping">the code stepper</a> but there are many tools to explore the recorded timelines,
which we are going to describe next.</p>
</div>
<div class="sect2">
<h3 id="_code_tool"><a class="anchor" href="#_code_tool"></a><a class="link" href="#_code_tool">3.1. Code tool</a></h3>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/code_tool_tab.png" alt="code tool tab">
</div>
</div>
<div class="paragraph">
<p>The code tool is the first of the <code>Flows</code> tab. It provides most of the functionality found in a traditional debugger.
You can use it to step over each expression, visualize values, locals and more.</p>
</div>
<div class="sect3">
<h4 id="_code_stepping"><a class="anchor" href="#_code_stepping"></a><a class="link" href="#_code_stepping">3.1.1. Code stepping</a></h4>
<div class="paragraph">
<p>The code tool allows you to step and "travel throught time" in two ways:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Use the controls at the top to step over your code in different ways.</p>
</li>
<li>
<p>Click on the highlighted forms to position the debugger at that point in time.</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/controls.png" alt="controls">
</div>
</div>
<div class="paragraph">
<p>For moving around using the controls we have two rows of buttons.</p>
</div>
<div class="paragraph">
<p>The second row of controls, the most important one, are the stepping controls.</p>
</div>
<div class="paragraph">
<p>From left to right they are :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Step over backwards, will make one step backwards always staying on the same frame.</p>
</li>
<li>
<p>Step backwards, will step backwards in time going into sub functions.</p>
</li>
<li>
<p>Step out, will position the debugger in the next step after this function was called.</p>
</li>
<li>
<p>Step forward, will step forward in time going into sub functions.</p>
</li>
<li>
<p>Step over forward, will make one step forwards always staying on the same frame.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The numbers at the center show <code>current_step_index / total_steps</code>. This means that a total of <code>total_steps</code> has been recorded
for this thread so far. Write any number (less than total_steps) on the text box to jump into that position in time.</p>
</div>
<div class="paragraph">
<p>The buttons around the step counter are :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Jump to the first step of the recording.</p>
</li>
<li>
<p>Jump to the last step of the recording.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>On the first row we have more controls, also for moving around in time.</p>
</div>
<div class="paragraph">
<p>From left to right we have :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Undo navigation</p>
</li>
<li>
<p>Redo navigation</p>
</li>
<li>
<p>Add a <a href="#_bookmarks">bookmark</a></p>
</li>
<li>
<p>The last stepping controls to the right are the <a href="#_power_stepping">power stepping</a> controls.</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Highlighting</div>
<div class="paragraph">
<p>Only the forms that were executed at least once for the current function frame will be highlighted.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This means that code can be un-highlighted for two reasons:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>there isn&#8217;t any recording for that part of the code</p>
</li>
<li>
<p>there is a recording but doesn&#8217;t belong to this function frame.</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/stepper_highlighting.png" alt="stepper highlighting">
</div>
</div>
<div class="paragraph">
<p>In the contrived example above we see we are stepping the <code>foo</code> function. All inside this function
body is highlighted but the bodies of the two anonymous functions for mapping and reducing. This
will only get highlighted once you step into their bodies.</p>
</div>
<div class="paragraph">
<p>In this case you are sure there are recordings for these functions bodies because the reduce is
non lazy, so if you keep stepping eventually you will get into their bodies, but there is a faster way.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/stepper_highlighting_2.png" alt="stepper highlighting 2">
</div>
</div>
<div class="paragraph">
<p>For this you can right click on any un-highlighted expression that you think there could be a recording for and
select <code>Jump forward here</code>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/stepper_highlighting_3.png" alt="stepper highlighting 3">
</div>
</div>
<div class="paragraph">
<p>This will make FlowStorm scan from the current point of the timeline searching forward for a value
recorded at that coordinate (if any) and move the stepper to that point in time.</p>
</div>
<div class="paragraph">
<p>You also have <code>Jump to first record here</code> which will scan from the beginning of the timeline and <code>Jump backwards here</code>
which will search backwards from the current position.</p>
</div>
</div>
<div class="sect3">
<h4 id="_power_stepping"><a class="anchor" href="#_power_stepping"></a><a class="link" href="#_power_stepping">3.1.2. Power stepping</a></h4>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/controls_power_custom.png" alt="controls power custom">
</div>
</div>
<div class="paragraph">
<p>The controls at the right are power stepping controls. They provide more powerfull ways of stepping through the code.</p>
</div>
<div class="paragraph">
<p>Clicking on the first, back, next or last buttons will navigate the timeline using the selected power stepping tool in the dropdown.</p>
</div>
<div class="paragraph">
<p>There are currently six power stepping tools :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>identity</code>, will step to the prev/next value which identity is the same as the current value.</p>
</li>
<li>
<p>'equality', will step to the prev/next value which is equals (clojure equality) to the current value.</p>
</li>
<li>
<p><code>same-coord</code> will step to the prev/next value for the same coordinate. This means it will move to the next recording in
the timeline for this exact place in the code you are currently in. You can also see it as take me to all the situations
when the current expression executed doesn&#8217;t matter how we got to it.</p>
</li>
<li>
<p><code>custom</code>, allows you to provide a predicate, which will be used to find the next step.
If you define it like <code>(fn [v] (map? v))</code> will make the power stepper step over all map values.</p>
</li>
<li>
<p><code>custom-same-coord</code>, the same as <code>custom</code> but fixed on the current coordinate like <code>same-coord</code>.</p>
</li>
<li>
<p><code>identity-other-thread</code>, will step to a position which identity is the same as the current value in a different thread.
Here the prev and next arrows do the same thing, it will just jump to the first position that matches this value on a
different thread. This has some limitations. If there are more than two threads working with this identity there is no way
of choosing which thread to go. If you need more control, checkout the <a href="#_programmable_debugging">programmable debugging</a>
section, specially the <code>find-expr-entry</code> function.</p>
</li>
<li>
<p><code>fn-call</code>, allows you to provide a function to step to.</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Custom stepping</div>
<div class="paragraph">
<p>Custom power stepping is only supported in Clojure now.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Power stepping automatically skips all values equals to <code>:flow-storm.power-step/skip</code>. This can be useful when combined
with <a href="#_dealing_with_mutable_values">snapshot-value</a> as a way of ignoring some of them, which provides a way of sampling
tight loops like in games.</p>
</div>
</div>
<div class="sect3">
<h4 id="_searching"><a class="anchor" href="#_searching"></a><a class="link" href="#_searching">3.1.3. Searching</a></h4>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/search_access.png" alt="search access">
</div>
</div>
<div class="paragraph">
<p>You can use the search tool to search over all your flow recorded expressions and then make the stepper jump to them.
You can find the search tool under <code>More tools &#8594; Search</code>.</p>
</div>
<div class="paragraph">
<p>There are multiple ways of searching:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>By pr-str</p>
</li>
<li>
<p>By data window current value</p>
</li>
<li>
<p>By predicate</p>
</li>
</ul>
</div>
<div class="sect4">
<h5 id="_searching_by_pr_str"><a class="anchor" href="#_searching_by_pr_str"></a><a class="link" href="#_searching_by_pr_str">Searching by pr-str</a></h5>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/search_pr_str.png" alt="search pr str">
</div>
</div>
<div class="paragraph">
<p>This type of search will walk over the selected threads expressions, converting their values to strings with <code>pr-str</code> up to the selected level and depth
and then checking if the resulting string contains your provided query string.</p>
</div>
</div>
<div class="sect4">
<h5 id="_searching_by_datawindow_value"><a class="anchor" href="#_searching_by_datawindow_value"></a><a class="link" href="#_searching_by_datawindow_value">Searching by DataWindow value</a></h5>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/search_data_window.png" alt="search data window">
</div>
</div>
<div class="paragraph">
<p>Searching by data window value allows you to select any of the current data windows and will search for the current selected data window value
over the selected threads expressions values using identity.</p>
</div>
</div>
<div class="sect4">
<h5 id="_searching_by_predicate"><a class="anchor" href="#_searching_by_predicate"></a><a class="link" href="#_searching_by_predicate">Searching by predicate</a></h5>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/search_pred.png" alt="search pred">
</div>
</div>
<div class="paragraph">
<p>Searching by predicate allows you to provide a Clojure predicate which will be used over all selected threads expressions values.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_loops"><a class="anchor" href="#_loops"></a><a class="link" href="#_loops">3.1.4. Loops</a></h4>
<div class="paragraph">
<p>Whenever you click a highlighted form that has been executed multiple times inside the same function call (any kind of loop),
instead of immediately jumping into it, FlowStorm will popup a menu, like in the picture below :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/loops.png" alt="loops">
</div>
</div>
<div class="paragraph">
<p>This is the loops navigation menu. It allows you to quickly move around interesting iterations of the loop.</p>
</div>
<div class="paragraph">
<p>The menu will display slightly different options depending on you current position. The <code>[FIRST] &#8230;&#8203;</code> and <code>[LAST] &#8230;&#8203;</code>
entries will always show, which allows you to quickly jump to the first and last iteration of the loop.</p>
</div>
<div class="paragraph">
<p>If you are currently before the loop, clicking into any expression inside the loop will show the first 20
values for the clicked expression.</p>
</div>
<div class="paragraph">
<p>If instead you are currently in a expression after the loop, clicking back to an expression inside the loop,
will show the last 20 values for the clicked expression.</p>
</div>
<div class="paragraph">
<p>Now if you are currently stepping inside the loop, clicking any other expression inside it will show you 10 values
before and 10 values after of your current position.</p>
</div>
<div class="paragraph">
<p>Clicking on any of this entries will take you to that position in time.</p>
</div>
<div class="paragraph">
<p>If this is not enough, and you want to see all the values taken by some expression along the loop, you can always
use the <a href="#_printer">printer tool</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_exceptions_debugging"><a class="anchor" href="#_exceptions_debugging"></a><a class="link" href="#_exceptions_debugging">3.1.5. Exceptions debugging</a></h4>
<div class="paragraph">
<p><code>FlowStorm</code> will capture all functions that didn&#8217;t return because an exception unwind the stack, even
when that exception was captured further and it didn&#8217;t bubble up.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/exceptions.png" alt="exceptions">
</div>
</div>
<div class="paragraph">
<p>When an unwind situation is recorded a combobox will show up in the toolbar, containing the functions names
together with the exceptions types. If you hover the mouse over any of them, a tooltip will display the exception message.</p>
</div>
<div class="paragraph">
<p>Clicking on any of them will position the stepper at that point in time so you can explore what happened before.</p>
</div>
<div class="paragraph">
<p>You can configure FlowStorm to automatically jump to exceptions with the <code>Config</code> menu by checking <code>Auto jump to exception</code>
which is disabled by default.</p>
</div>
</div>
<div class="sect3">
<h4 id="_locals"><a class="anchor" href="#_locals"></a><a class="link" href="#_locals">3.1.6. Locals</a></h4>
<div class="paragraph">
<p>The locals panel will show the locals visible for the current point in time and their values at binding time.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/locals.png" alt="locals">
</div>
</div>
<div class="paragraph">
<p>Right clicking on them will show a menu where you can :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>define all</p>
</li>
<li>
<p>define the value with a name, so you can use it at the repl</p>
</li>
<li>
<p>inspect the value with a <a href="#_data_windows">data window</a></p>
</li>
<li>
<p>tap the value as with <code>tap&gt;</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>Define all</code> will define all the bindings currently visible in the locals pane in the current form namespace.
This is useful for trying things at your editor as described here <a href="https://www.cognitect.com/blog/2017/6/5/repl-debugging-no-stacktrace-required" class="bare">https://www.cognitect.com/blog/2017/6/5/repl-debugging-no-stacktrace-required</a></p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Locals and mutable values</div>
<div class="paragraph">
<p>The Locals pane will show the value of each binding for a symbol at binding time, which are the same thing
no matter where you are in the current block when working with immutable objects, but not when working with mutable ones.
If what was bound was muttable in any way, you will be seeing the value at binding time, and not at current time.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_stack"><a class="anchor" href="#_stack"></a><a class="link" href="#_stack">3.1.7. Stack</a></h4>
<div class="paragraph">
<p>The stack panel will always show the current stacktrace. Be aware that the stacktrace
only include functions calls that had been recorded, so if you aren&#8217;t recording everything
there will be gaps.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/stack.png" alt="stack">
</div>
</div>
<div class="paragraph">
<p>Double clicking on any of the stack entries will make the debugger jump to that point in time.</p>
</div>
</div>
<div class="sect3">
<h4 id="_value_panels"><a class="anchor" href="#_value_panels"></a><a class="link" href="#_value_panels">3.1.8. Value panels</a></h4>
<div class="paragraph">
<p>Value panels show in many places in <em>FlowStorm</em>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/value_panels2.png" alt="value panels2">
</div>
</div>
<div class="paragraph">
<p>The value panel in the code tool always display a pretty print of the current expression value.</p>
</div>
<div class="paragraph">
<p>You can configure the print-level and print-meta for the pretty printing by using the controls at the top.</p>
</div>
<div class="paragraph">
<p>The value panel showing the current expression in the code stepper is a little bit special since it also
contains a <a href="#_data_windows">data window</a> tab which allows you to quickly navigate the value or give it custom
visualizations.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/value_panels1.png" alt="value panels1">
</div>
</div>
<div class="sect4">
<h5 id="_define_value_for_repl"><a class="anchor" href="#_define_value_for_repl"></a><a class="link" href="#_define_value_for_repl">Define value for repl</a></h5>
<div class="paragraph">
<p>Use the <code>def</code> button to define a var pointing to the current inspector value.</p>
</div>
<div class="paragraph">
<p>You can use / to provide a namespace, otherwise will be defined under [cljs.]user</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_goto_to_fileline"><a class="anchor" href="#_goto_to_fileline"></a><a class="link" href="#_goto_to_fileline">3.1.9. Goto to file:line</a></h4>
<div class="paragraph">
<p>Clicking on the <code>Actions&#8594;Goto file:line</code> menu allows you to search and jump to the first recording of a expression
with a file and line, given that one exists.</p>
</div>
<div class="paragraph">
<p>It will ask you for a file and line in the format of <code>&lt;class-path-file-path&gt;:&lt;line&gt;</code>.</p>
</div>
<div class="paragraph">
<p>If you have a file like <code>src/org/my_app/core.clj</code> and you are interested in expressions evaluating on like 42
you should search like <code>org/my_app/core.clj:42</code>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_call_stack_tree_tool"><a class="anchor" href="#_call_stack_tree_tool"></a><a class="link" href="#_call_stack_tree_tool">3.2. Call Stack tree tool</a></h3>
<div class="paragraph">
<p>The call stack tree tool is the second one of the <code>Flows</code> tab. It allows you to see the execution flow by expanding its call stack tree.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/callstack_tool_tab.png" alt="callstack tool tab">
</div>
</div>
<div class="paragraph">
<p>The call stack tree is useful for a high level overview of a complex execution and also as a tool for quickly moving through time.</p>
</div>
<div class="paragraph">
<p>You can jump to any point in time by double clicking on a node or by right clicking and on the context menu selecting <code>Step code</code>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/callstack_tree.png" alt="callstack tree">
</div>
</div>
<div class="paragraph">
<p>Use the button at the top left corner of the tree tool to show the current frame of the debugger in the tree.</p>
</div>
<div class="paragraph">
<p>There are also two <a href="#_value_panels">value panels</a> at the bottom that show the arguments and return value for the currently selected function call.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Disabling the call stack tree tool</div>
<div class="paragraph">
<p>The call stack tree tool can be enable/disable on the fly if you are not using it and performance is an issue,
since keeping it updated can be expensive.
You can disable it from the Config menu or via the <code>flowstorm.callTreeUpdate=false</code> JVM prop.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_functions_tool"><a class="anchor" href="#_functions_tool"></a><a class="link" href="#_functions_tool">3.3. Functions tool</a></h3>
<div class="paragraph">
<p>The functions tool is the third one of the <code>Flows</code> tab.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/functions_tool_tab.png" alt="functions tool tab">
</div>
</div>
<div class="paragraph">
<p>It shows a list of all traced functions sort by how many times the have been called.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/functions_calls.png" alt="functions calls">
</div>
</div>
<div class="paragraph">
<p>Normal functions will be colored black, multimethods magenta and types/records protocols/interfaces implementations in green.</p>
</div>
<div class="paragraph">
<p>Together with the <a href="#_call_stack_tree_tool">call stack tree</a> it provides a high level overview of a thread execution, and allows you to
jump through time much faster than single stepping.</p>
</div>
<div class="paragraph">
<p>You can search over the functions list by using the bar at the top.</p>
</div>
<div class="sect3">
<h4 id="_function_calls"><a class="anchor" href="#_function_calls"></a><a class="link" href="#_function_calls">3.3.1. Function calls</a></h4>
<div class="paragraph">
<p>Clicking on the calls counter of any function will display all function calls on the right sorted by time.
Each line will show the arguments vector for each call, and their return value.
Use the check boxes at the top to hide some of the arguments.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/function_calls.png" alt="function calls">
</div>
</div>
<div class="paragraph">
<p>Double clicking on any row in the functions call list will jump to the stepper at that point in time.</p>
</div>
<div class="paragraph">
<p>You can also use the <code>args</code> and <code>ret</code> buttons to open the values on the inspector.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_multi_thread_timeline"><a class="anchor" href="#_multi_thread_timeline"></a><a class="link" href="#_multi_thread_timeline">3.4. Multi-thread timeline</a></h3>
<div class="paragraph">
<p>You can use this tool to record, display and navigate a total order of your recordings in a timeline.
This can be used, for example, to visualize how multiple threads expressions interleave, which is sometimes useful to debug race conditions.</p>
</div>
<div class="paragraph">
<p>You enable/disable the multi-thread timeline recording using its button on the toolbar. Recording on the multi-thread
timeline will make your program execution a little slower so it is recommended to have it paused unless you need it.</p>
</div>
<div class="paragraph">
<p>When you have something recorded on the multi-thread timeline you access the tool from the top right corner.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/multi_timeline_access.png" alt="multi timeline access">
</div>
</div>
<div class="paragraph">
<p>As an example, let&#8217;s say you record the execution this function :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">run-parallel</span><span class="w"> </span><span class="p">[]</span><span class="w">
  </span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="p">(</span><span class="nb">range</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w">
       </span><span class="p">(</span><span class="nf">pmap</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nf">factorial</span><span class="w"> </span><span class="n">i</span><span class="p">)))</span><span class="w">
       </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="nb">+</span><span class="p">)))</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>By opening the tool a window like this should pop up :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/timeline.png" alt="timeline">
</div>
</div>
<div class="paragraph">
<p>As you can see the timeline tool displays a linear representation of your expressions. Times flows from top to bottom and
each thread gets assigned a different color. Every time a function is called or returns you will see it under the <code>Function</code>
column, and for each expression executed you will see a row with its <code>Expression</code> and <code>Value</code>.</p>
</div>
<div class="paragraph">
<p>Double clicking any row will make your code stepper (on the main window) jump to the code at that point in time.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Big recordings timeline</div>
<div class="paragraph">
<p>Rendering the timeline needs some processing to render each sub-form and print each value so be aware it could be slow
if you try it on big recordings.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>There is also a <code>Only functions?</code> checkbox at the top that will retrieve only function calls and can be used to visualize
the threads interleaving at a higher level.</p>
</div>
</div>
<div class="sect2">
<h3 id="_printer"><a class="anchor" href="#_printer"></a><a class="link" href="#_printer">3.5. Printer</a></h3>
<div class="paragraph">
<p><em>FlowStorm</em> has a lot of functionality to replace printing to the console as a debugging method since most of the time it is pretty
inefficient. Nonetheless, sometimes adding a bunch of print lines to specific places in your code is a very powerful way
of understanding execution.</p>
</div>
<div class="paragraph">
<p>For this cases <em>FlowStorm</em> has the <code>Printer tool</code>, which allows you to define, manage and visualize print points, without the need
of re running your code. It will work on your recordings as everything else.</p>
</div>
<div class="paragraph">
<p>You can add and re run print points over your recordings as many times as you need. To add a print point, just right click on any
recorded expression.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/printer_add.png" alt="printer add">
</div>
</div>
<div class="paragraph">
<p>It will ask you for a couple optional fields.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/printer_add_box.png" alt="printer add box">
</div>
</div>
<div class="paragraph">
<p>The <code>Message format</code> is the "println text". A message to identify the print on the printer output. Here you can use any text, in which you can
optionally use <code>%s</code> for the printed value, same as you would use it with format.</p>
</div>
<div class="paragraph">
<p>The <code>Expression</code> field can be use to apply a transformer function over the value before printing it. Useful when you want to see a part of the value.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/printer_access.png" alt="printer access">
</div>
</div>
<div class="paragraph">
<p>After you add them, you can access the <code>Printers tool</code> by navigating to <code>More tools &#8594; Printers</code>.</p>
</div>
<div class="paragraph">
<p>The threads selector allows you to select the thread the prints are going to run on.
Leaving it blank will run prints over all threads recordings (checkout the notes for caveats).
Clicking the <code>refresh</code> button will [re]run the printing again over the current recordings.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/printer.png" alt="printer">
</div>
</div>
<div class="paragraph">
<p>You can tweak your prints at any time, like changing the print-length, print-level, message, transform-fn or just temporarily disable any of them.
When you are ok re-setting you prints, just click refresh and they will print again.</p>
</div>
<div class="paragraph">
<p>Double clicking on any printed line will jump to the Flows code tab, with the debugger pointed to the expression that generated the print.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<div class="title">Important</div>
</td>
<td class="content">
<div class="title">Multi-thread prints order</div>
<div class="paragraph">
<p>If you select <code>All</code> threads, and have a multi-thread timeline recording, then the printer will use it and you can use prints to debug threads
interleaving for example, but if you run your printers with <code>All</code> threads selected without a multi-thread timeline recording they will print
sorted by thread and not in the order they happened.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_bookmarks"><a class="anchor" href="#_bookmarks"></a><a class="link" href="#_bookmarks">3.6. Bookmarks</a></h3>
<div class="paragraph">
<p>Bookmarks are another quick way of jumping around in code and they can be added from your code or the FlowStorm UI.</p>
</div>
<div class="paragraph">
<p>You can find you bookmarks on the top menu <code>View &#8594; Bookmarks</code>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/bookmarks.png" alt="bookmarks">
</div>
</div>
<div class="paragraph">
<p>Double clicking on any bookmark will make the debugger jump back to its position.</p>
</div>
<div class="sect3">
<h4 id="_code_bookmarks"><a class="anchor" href="#_code_bookmarks"></a><a class="link" href="#_code_bookmarks">3.6.1. Code bookmarks</a></h4>
<div class="paragraph">
<p>You add code bookmarks by adding the <code>(bookmark)</code> statement to your code, which optionally accepts a label.</p>
</div>
<div class="paragraph">
<p>The first time a bookmark statement is executed it will make the FlowStorm UI jump to it. Since this behavior
is similar to a <code>debugger</code> statement in languages like Javascript, it is also aliased as <code>(debugger)</code> so you can
use whichever you prefer.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">ClojureScript support</div>
<div class="paragraph">
<p>This is currently only supported when using ClojureScriptStorm &gt;= 1.11.132-9</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_ui_bookmarks"><a class="anchor" href="#_ui_bookmarks"></a><a class="link" href="#_ui_bookmarks">3.6.2. UI bookmarks</a></h4>
<div class="paragraph">
<p>UI bookmarks are useful when you find yourself jumping around, trying to understand a complex execution. They enable
you to mark execution positions so you can come back to them later.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/bookmarks_add_btn.png" alt="bookmarks add btn">
</div>
</div>
<div class="paragraph">
<p>You can bookmark the current position by pressing the bookmark button in the code tool, next to your stepping controls.
It will ask you the bookmark description.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_browser_tool"><a class="anchor" href="#_browser_tool"></a><a class="link" href="#_browser_tool">4. Browser tool</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The browser tool is pretty straight forward. It allows you to navigate your namespaces and vars,
and provides ways of <a href="#_controlling_instrumentation">managing what gets instrumented</a>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/browser.png" alt="browser">
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_outputs_tool"><a class="anchor" href="#_outputs_tool"></a><a class="link" href="#_outputs_tool">5. Outputs tool</a></h2>
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="user_guide_images/outputs.png" alt="outputs">
</div>
</div>
<div class="paragraph">
<p>The outputs tool can be used instead of your normal IDE/Editor panel to visualize your evaluations
results, your taps outputs and your <code><strong>out</strong></code> and <code><strong>err</strong></code> streams writes (like printlns).</p>
</div>
<div class="paragraph">
<p>The advantages being :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Custom visualizations</p>
</li>
<li>
<p>Quick nested values navigation</p>
</li>
<li>
<p>Quick taps values navigation</p>
</li>
<li>
<p>Datafy nav navigation</p>
</li>
<li>
<p>Access to all previously tapped values</p>
</li>
<li>
<p>Access to the last 10 evaluated values (instead of just <code>*1</code> and <code>*2</code>)</p>
</li>
<li>
<p>Ability to search tapped values in Flows</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The taps visualization system works out of the box while the evals result and printing capture currently
depends on you using nrepl and starting with the flow-storm middleware. Checkout the outputs setup
section for instructions.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">ClojureScript support</div>
<div class="paragraph">
<p>Only the taps viewer is currently supported on ClojureScript. The last evaluations
and the out and err streams capture aren&#8217;t supported yet.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect2">
<h3 id="_middleware_setup"><a class="anchor" href="#_middleware_setup"></a><a class="link" href="#_middleware_setup">5.1. Middleware setup</a></h3>
<div class="paragraph">
<p>For using all the features in the Outputs tool you need to be using nrepl and start your repl with
<code>flow-storm.nrepl.middleware/wrap-flow-storm</code> middleware.</p>
</div>
<div class="paragraph">
<p>If you use Cider for example you can add it to <code>cider-jack-in-nrepl-middlewares</code> via customizing the global
value or by using <code>.dir-locals.el</code>.</p>
</div>
</div>
<div class="sect2">
<h3 id="_output_data_window"><a class="anchor" href="#_output_data_window"></a><a class="link" href="#_output_data_window">5.2. Output data window</a></h3>
<div class="paragraph">
<p>The top panel is a <a href="#_data_windows">data window</a> for displaying evaluations and taps.
As soon as you evaluate or tap something it will be displayed here.</p>
</div>
</div>
<div class="sect2">
<h3 id="_last_evals"><a class="anchor" href="#_last_evals"></a><a class="link" href="#_last_evals">5.3. Last evals</a></h3>
<div class="paragraph">
<p>The last evals pane gives you access to the last 10 evaluation results, same as <code>*1</code> and <code>*2</code>.</p>
</div>
<div class="paragraph">
<p>Click on any value to display it on the top data window.</p>
</div>
</div>
<div class="sect2">
<h3 id="_taps"><a class="anchor" href="#_taps"></a><a class="link" href="#_taps">5.4. Taps</a></h3>
<div class="paragraph">
<p>Everytime <em>FlowStorm</em> starts, it will add a tap, so whenever you <code>tap&gt;</code> something
it will show on the taps list.</p>
</div>
<div class="paragraph">
<p>Click on any value to display it on the top data window.</p>
</div>
<div class="paragraph">
<p>If the tapped value has also been recorded as an expression in Flows, you can right click on it
and run <code>Search value on Flows</code> to move the debugger to that point in time.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Search value on Flows</div>
<div class="paragraph">
<p>Be aware that if the code that taps your value is something like <code>(tap&gt; :a-key)</code> you won&#8217;t be able to jump
to it using this, because <code>:a-key</code> isn&#8217;t a value recorded by <em>FlowStorm</em>, while if the tapping
code is like <code>(tap&gt; some-bind)</code> or <code>(tap&gt; (+ 2 3))</code> or the tapping of any other expression
you should be able to jump to it.
So if you want to use this functionality as a "mark" so you can quickly jump to different parts of
the recordings from the Taps tool, you can do it like <code>(tap&gt; (str :my-mark))</code></p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>A <code>#tap</code> tag will also be available, which will tap and return so you can use it like <code>(+ 1 2 #tap (* 3 4))</code>
Use the <code>clear</code> button to clear the list.</p>
</div>
<div class="paragraph">
<p>There is also <code>#tap-stack-trace</code>. It will tap the current stack trace.</p>
</div>
</div>
<div class="sect2">
<h3 id="_out_and_err_streams"><a class="anchor" href="#_out_and_err_streams"></a><a class="link" href="#_out_and_err_streams">5.5. Out and Err streams</a></h3>
<div class="paragraph">
<p>Everything written on <code><strong>out</strong></code> or <code><strong>err</strong></code> will be captured and displayed on the bottom panel.
You can copy anything from this area with normal tools.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_data_windows"><a class="anchor" href="#_data_windows"></a><a class="link" href="#_data_windows">6. Data Windows</a></h2>
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window.png" alt="data window">
</div>
</div>
<div class="paragraph">
<p>Data Windows are a user extensible tool to visualize and explore your data. Their role is to support :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>a way to navigate nested structures in a lazy way</p>
</li>
<li>
<p>visualize and navigate metadata</p>
</li>
<li>
<p>multiple visualizations for each value</p>
</li>
<li>
<p>lazy/infinite sequences navigation</p>
</li>
<li>
<p>a way to define the current sub-values so you can use them at the repl</p>
</li>
<li>
<p>a mechanism for realtime data visualization</p>
</li>
<li>
<p>clojure.datafy navigation out of the box</p>
</li>
<li>
<p>tools for the user to add custom visualizations on the fly</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The next sections will explore each of them.</p>
</div>
<div class="sect2">
<h3 id="_data_navigation"><a class="anchor" href="#_data_navigation"></a><a class="link" href="#_data_navigation">6.1. Data navigation</a></h3>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window_dig.png" alt="data window dig">
</div>
</div>
<div class="paragraph">
<p>You can navigate into any key or value by clicking on it.</p>
</div>
<div class="paragraph">
<p>Use the breadcrumbs at the top to navigate back.</p>
</div>
</div>
<div class="sect2">
<h3 id="_metadata_navigation"><a class="anchor" href="#_metadata_navigation"></a><a class="link" href="#_metadata_navigation">6.2. Metadata navigation</a></h3>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window_meta.png" alt="data window meta">
</div>
</div>
<div class="paragraph">
<p>If any value contains metadata, it will be shown at the top. Clicking on it will make the data window
navigate into it.</p>
</div>
</div>
<div class="sect2">
<h3 id="_multiple_visualizers"><a class="anchor" href="#_multiple_visualizers"></a><a class="link" href="#_multiple_visualizers">6.3. Multiple visualizers</a></h3>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window_multiple_viz.png" alt="data window multiple viz">
</div>
</div>
<div class="paragraph">
<p>You can change how to display your current value by using the visualizers selector dropdown at the top.</p>
</div>
</div>
<div class="sect2">
<h3 id="_sequences"><a class="anchor" href="#_sequences"></a><a class="link" href="#_sequences">6.4. Sequences</a></h3>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window_seqable.png" alt="data window seqable">
</div>
</div>
<div class="paragraph">
<p>The seqable visualizer allows you to navigate all kind of sequences (even infinite ones) by bringing more pages on demand.</p>
</div>
<div class="paragraph">
<p>Click on <code>More</code> to bring the next page in.</p>
</div>
</div>
<div class="sect2">
<h3 id="_defining_values"><a class="anchor" href="#_defining_values"></a><a class="link" href="#_defining_values">6.5. Defining values</a></h3>
<div class="paragraph">
<p>You can always define a var for the current value being shown on any data window by clicking the <code>def</code> button.
Clicking on it will raise a popup asking for a symbol name. If you don&#8217;t provide a fully qualified symbol
it will define the var under <code>user</code> or <code>cljs.user</code> if you are in ClojureScript.</p>
</div>
<div class="paragraph">
<p>A quick way to use it is to provide a short name, let&#8217;s say <code>foo</code>, and then access it from your
code like <code>user/foo</code>.</p>
</div>
</div>
<div class="sect2">
<h3 id="_realtime_visualizations"><a class="anchor" href="#_realtime_visualizations"></a><a class="link" href="#_realtime_visualizations">6.6. Realtime visualizations</a></h3>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window_realtime.png" alt="data window realtime">
</div>
</div>
<div class="paragraph">
<p>DataWindows not only support displaying and navigating values, but also updating them in real time from
your application.</p>
</div>
<div class="paragraph">
<p>From your program&#8217;s code you can always create a data window with :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">flow-storm.api/data-window-push-val</span><span class="w"> </span><span class="no">:changing-long-dw-id</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s">"a-long"</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>by providing a data window id, a value, and optionally the initial breadcrumb label.</p>
</div>
<div class="paragraph">
<p>But you can also update it (given that the selected visualizer supports updating like :scope for numbers) with :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">flow-storm.api/data-window-val-update</span><span class="w"> </span><span class="no">:changing-long-dw-id</span><span class="w"> </span><span class="mf">0.5</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This <code>data-window-val-update</code> is pretty useful when called from loops or refs watches, specially paired
with a custom visualizer.</p>
</div>
</div>
<div class="sect2">
<h3 id="_clojure_datafynav"><a class="anchor" href="#_clojure_datafynav"></a><a class="link" href="#_clojure_datafynav">6.7. Clojure datafy/nav</a></h3>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window_datafy_nav.png" alt="data window datafy nav">
</div>
</div>
<div class="paragraph">
<p>Data Windows support datafy nav out of the box. The data window will always be showing the result of
<code>clojure.datafy/datafy</code> of a value. For maps or vectors where keys provide navigation it will automatically
add a blue arrow next to the value.</p>
</div>
<div class="paragraph">
<p>Clicking on the value will just dig the data, while clicking on the blue arrow will navigate as with
<code>clojure.datafy/nav</code> applied to that collection on that key.</p>
</div>
</div>
<div class="sect2">
<h3 id="_eql_pprint_visualizer"><a class="anchor" href="#_eql_pprint_visualizer"></a><a class="link" href="#_eql_pprint_visualizer">6.8. EQL pprint visualizer</a></h3>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/eql_visualizer_0.png" alt="eql visualizer 0">
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/eql_visualizer_1.png" alt="eql visualizer 1">
</div>
</div>
<div class="paragraph">
<p>The <code>eql-query-pprint</code> visualizer allows you to explore your data "entities" by looking at subsets of it
using queries similar to datomic pull queries like in the screenshots above.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Disable by default</div>
<div class="paragraph">
<p>The EQL query pprint is disable by default. To enable it call <code>(flow-storm.runtime.values/register-eql-query-pprint-extractor)</code>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>By entities it means maps which contains only keywords as their keys. Every other collection
is just traversed.</p>
</div>
<div class="paragraph">
<p>This are all valid queries :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>[*]</code></p>
</li>
<li>
<p><code>[:name]</code></p>
</li>
<li>
<p><code>[:name :age :vehicles]</code></p>
</li>
<li>
<p><code>[:name :age {:vehicles [:type]}]</code></p>
</li>
<li>
<p><code>[:name :age {:vehicles [?]}]</code></p>
</li>
<li>
<p><code>[:name {:vehicles [*]}]</code></p>
</li>
<li>
<p><code>[:name :age {:vehicles [:type {:seats [?]}]}]</code></p>
</li>
<li>
<p><code>[:name :age {:vehicles [:type {:seats [:kind]}]}]</code></p>
</li>
<li>
<p><code>[:name {:houses [:rooms]}]</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>*</code> symbol means include all keys, while the <code>?</code> symbol means just list the keys, which helps
exploring big nested maps with many keys.</p>
</div>
</div>
<div class="sect2">
<h3 id="_custom_visualizers"><a class="anchor" href="#_custom_visualizers"></a><a class="link" href="#_custom_visualizers">6.9. Custom visualizers</a></h3>
<div class="paragraph">
<p>An important aspect of Data Windows is to be able to provide custom visualizers on the fly.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s say we have model a chess board as a set of maps which represent our pieces.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">chess-board</span><span class="w">
  </span><span class="o">#</span><span class="p">{{</span><span class="no">:kind</span><span class="w"> </span><span class="no">:king</span><span class="w">  </span><span class="no">:player</span><span class="w"> </span><span class="no">:white</span><span class="w"> </span><span class="no">:pos</span><span class="w"> </span><span class="p">[</span><span class="mi">0</span><span class="w"> </span><span class="mi">5</span><span class="p">]}</span><span class="w">
    </span><span class="p">{</span><span class="no">:kind</span><span class="w"> </span><span class="no">:rook</span><span class="w">  </span><span class="no">:player</span><span class="w"> </span><span class="no">:white</span><span class="w"> </span><span class="no">:pos</span><span class="w"> </span><span class="p">[</span><span class="mi">5</span><span class="w"> </span><span class="mi">1</span><span class="p">]}</span><span class="w">
    </span><span class="p">{</span><span class="no">:kind</span><span class="w"> </span><span class="no">:pawn</span><span class="w">  </span><span class="no">:player</span><span class="w"> </span><span class="no">:white</span><span class="w"> </span><span class="no">:pos</span><span class="w"> </span><span class="p">[</span><span class="mi">5</span><span class="w"> </span><span class="mi">3</span><span class="p">]}</span><span class="w">
    </span><span class="p">{</span><span class="no">:kind</span><span class="w"> </span><span class="no">:king</span><span class="w">  </span><span class="no">:player</span><span class="w"> </span><span class="no">:black</span><span class="w"> </span><span class="no">:pos</span><span class="w"> </span><span class="p">[</span><span class="mi">7</span><span class="w"> </span><span class="mi">2</span><span class="p">]}</span><span class="w">
    </span><span class="p">{</span><span class="no">:kind</span><span class="w"> </span><span class="no">:pawn</span><span class="w">  </span><span class="no">:player</span><span class="w"> </span><span class="no">:black</span><span class="w"> </span><span class="no">:pos</span><span class="w"> </span><span class="p">[</span><span class="mi">6</span><span class="w"> </span><span class="mi">6</span><span class="p">]}</span><span class="w">
    </span><span class="p">{</span><span class="no">:kind</span><span class="w"> </span><span class="no">:queen</span><span class="w"> </span><span class="no">:player</span><span class="w"> </span><span class="no">:black</span><span class="w"> </span><span class="no">:pos</span><span class="w"> </span><span class="p">[</span><span class="mi">3</span><span class="w"> </span><span class="mi">1</span><span class="p">]}})</span><span class="w">

</span><span class="p">(</span><span class="nf">flow-storm.api/data-window-push-val</span><span class="w"> </span><span class="no">:chess-board-dw</span><span class="w"> </span><span class="n">chess-board</span><span class="w"> </span><span class="s">"chess-board"</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>If we open a data window with <code>data-window-push-val</code> we are going to see something like this :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window_custom1.png" alt="data window custom1">
</div>
</div>
<div class="paragraph">
<p>but we can do better, we can create a custom visualizer so we can see it like this :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/data_window_custom2.png" alt="data window custom2">
</div>
</div>
<div class="paragraph">
<p>Data visualization in FlowStorm is composed of two things:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>a data aspect extractor, which runs on the runtime process, and will build data for the visualization part</p>
</li>
<li>
<p>a visualizer, which runs on the debugger process, and will render extracted data for a value using javafx</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For a basic Clojure session everything will be running under the same process, but this is not the case for ClojureScript
or remote Clojure.</p>
</div>
<div class="paragraph">
<p>First let&#8217;s require some namespaces :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">require</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">flow-storm.api</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">fsa</span><span class="p">])</span><span class="w">
</span><span class="p">(</span><span class="nf">require</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">flow-storm.debugger.ui.data-windows.visualizers</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">viz</span><span class="p">])</span><span class="w">
</span><span class="p">(</span><span class="nf">require</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">flow-storm.runtime.values</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">fs-values</span><span class="p">])</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We can register a custom visualizer by calling <code>register-visualizer</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">viz/register-visualizer</span><span class="w">
     </span><span class="p">{</span><span class="no">:id</span><span class="w"> </span><span class="no">:my-viz</span><span class="w">
      </span><span class="no">:pred</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="nb">val</span><span class="p">]</span><span class="w"> </span><span class="p">)</span><span class="w">
      </span><span class="no">:on-create</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="nb">val</span><span class="p">]</span><span class="w"> </span><span class="p">{</span><span class="no">:fx/node</span><span class="w"> </span><span class="no">:any-java-fx-node-that-renders-the-value</span><span class="w">
                            </span><span class="no">:more-ctx-data</span><span class="w"> </span><span class="no">:anything</span><span class="p">})</span><span class="w">
      </span><span class="c1">;; OPTIONALLY</span><span class="w">
      </span><span class="no">:on-update</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="nb">val</span><span class="w"> </span><span class="n">created-ctx-map</span><span class="w"> </span><span class="p">{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">new-val</span><span class="p">]}]</span><span class="w"> </span><span class="p">)</span><span class="w">
      </span><span class="no">:on-destroy</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">created-ctx-map</span><span class="p">]</span><span class="w"> </span><span class="p">)</span><span class="w">
      </span><span class="p">})</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The important part there are <code>:id</code>, <code>:pred</code>, and <code>:on-create</code>.</p>
</div>
<div class="paragraph">
<p>The <code>:id</code> will be the one displayed on the visualizers dropdown, and re-registering a visualizer
with the same id will replace the previous one.</p>
</div>
<div class="paragraph">
<p><code>:pred</code> is a predicate on the data extracted from values, it should return true if this visualizer
can handle the value.</p>
</div>
<div class="paragraph">
<p>And <code>:on-create</code> will be a function that receives this value and renders a java fx node.
The val passed to on-create will also contain two special keywords :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>:flow-storm.debugger.ui.data-windows.data-windows/dw-id The id of the data windows it&#8217;s being draw on</p>
</li>
<li>
<p>:flow-storm.debugger.ui.data-windows.data-windows/preferred-size (could be :small)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Optionally you can provide <code>:on-update</code> and <code>:on-destroy</code>.</p>
</div>
<div class="paragraph">
<p><code>:on-update</code> will receive values from the runtime via <code>fsa/data-window-val-update</code>. It will also get a handle to
the original value (the one that created the DataWindow) and whatever map was returned by <code>:on-create</code>.</p>
</div>
<div class="paragraph">
<p><code>:on-destroy</code> will be called everytime a visualizer gets removed, because you swapped your current visualizer
or because you went back with breadcrums. It can be useful in case you need to clear resources created by
<code>:on-create</code>.</p>
</div>
<div class="paragraph">
<p><code>:pred</code> and <code>:on-create</code> will not receive the original value but the extracted aspects of it after
all registered extractors run.</p>
</div>
<div class="paragraph">
<p>You can check the data available to your visualizer for a value in a data window by calling :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">viz/data-window-current-val</span><span class="w"> </span><span class="no">:chess-board-dw</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>If the data already extracted from your value is not enough for your visualizer you can register
another extractor.</p>
</div>
<div class="sect3">
<h4 id="_data_aspect_extraction"><a class="anchor" href="#_data_aspect_extraction"></a><a class="link" href="#_data_aspect_extraction">6.9.1. Data aspect extraction</a></h4>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">fs-values/register-data-aspect-extractor</span><span class="w">
   </span><span class="p">{</span><span class="no">:id</span><span class="w"> </span><span class="no">:chess-board</span><span class="w">
    </span><span class="no">:pred</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="nb">val</span><span class="w"> </span><span class="n">_</span><span class="p">]</span><span class="w">
            </span><span class="p">(</span><span class="nb">and</span><span class="w"> </span><span class="p">(</span><span class="nf">set?</span><span class="w"> </span><span class="nb">val</span><span class="p">)</span><span class="w">
                 </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">kind</span><span class="w"> </span><span class="n">player</span><span class="w"> </span><span class="n">pos</span><span class="p">]}</span><span class="w"> </span><span class="p">(</span><span class="nb">first</span><span class="w"> </span><span class="nb">val</span><span class="p">)]</span><span class="w">
                   </span><span class="p">(</span><span class="nb">and</span><span class="w"> </span><span class="n">kind</span><span class="w"> </span><span class="n">player</span><span class="w"> </span><span class="n">pos</span><span class="p">))))</span><span class="w">
    </span><span class="no">:extractor</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">board</span><span class="w"> </span><span class="n">_</span><span class="p">]</span><span class="w"> </span><span class="p">{</span><span class="no">:chess/board</span><span class="w"> </span><span class="n">board</span><span class="p">})})</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>In this case we are going to register and extractor that will only run for vals which are sets and
contains at least one element which is a map with <code>:kind</code>, <code>:player</code> and <code>:pos</code>.
The extracted data will be the entire board.</p>
</div>
<div class="paragraph">
<p>All ids of extractors that applied for a value will be appended under <code>::fs-values/kinds</code> of the value
as you will see next.</p>
</div>
</div>
<div class="sect3">
<h4 id="_visualizers"><a class="anchor" href="#_visualizers"></a><a class="link" href="#_visualizers">6.9.2. Visualizers</a></h4>
<div class="paragraph">
<p>Now we can register a visualizer that will show only on values which contains a :chess-board kind.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nb">import</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">javafx.scene.layout</span><span class="w"> </span><span class="n">GridPane</span><span class="p">])</span><span class="w">
</span><span class="p">(</span><span class="nb">import</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">javafx.scene.control</span><span class="w"> </span><span class="n">Label</span><span class="p">])</span><span class="w">

</span><span class="p">(</span><span class="nf">viz/register-visualizer</span><span class="w">
   </span><span class="p">{</span><span class="no">:id</span><span class="w"> </span><span class="no">:chess-board</span><span class="w">
    </span><span class="c1">;; only be available if the chess-board data extractor run on this value</span><span class="w">
    </span><span class="no">:pred</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="nb">val</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nb">contains?</span><span class="w"> </span><span class="p">(</span><span class="no">::fs-values/kinds</span><span class="w"> </span><span class="nb">val</span><span class="p">)</span><span class="w"> </span><span class="no">:chess-board</span><span class="p">))</span><span class="w">

    </span><span class="c1">;; use the chess/board info to render a board with java fx</span><span class="w">
    </span><span class="no">:on-create</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">chess/board</span><span class="p">]}]</span><span class="w">
                 </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">kind-&gt;sprite</span><span class="w"> </span><span class="p">{</span><span class="no">:king</span><span class="w"> </span><span class="s">"♚"</span><span class="w"> </span><span class="no">:queen</span><span class="w"> </span><span class="s">"♛"</span><span class="w"> </span><span class="no">:rook</span><span class="w"> </span><span class="s">"♜"</span><span class="w"> </span><span class="no">:bishop</span><span class="w"> </span><span class="s">"♝"</span><span class="w"> </span><span class="no">:knight</span><span class="w"> </span><span class="s">"♞"</span><span class="w"> </span><span class="no">:pawn</span><span class="w"> </span><span class="s">"♟"</span><span class="p">}</span><span class="w">
                       </span><span class="n">pos-&gt;piece</span><span class="w"> </span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">board</span><span class="w">
                                       </span><span class="p">(</span><span class="nf">mapv</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nb">vector</span><span class="w"> </span><span class="p">(</span><span class="no">:pos</span><span class="w"> </span><span class="n">%</span><span class="p">)</span><span class="w"> </span><span class="n">%</span><span class="p">))</span><span class="w">
                                       </span><span class="p">(</span><span class="nb">into</span><span class="w"> </span><span class="p">{}))]</span><span class="w">
                   </span><span class="p">{</span><span class="no">:fx/node</span><span class="w"> </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">gp</span><span class="w"> </span><span class="p">(</span><span class="nf">GridPane.</span><span class="p">)]</span><span class="w">
                               </span><span class="p">(</span><span class="nb">doall</span><span class="w">
                                </span><span class="p">(</span><span class="k">for</span><span class="w"> </span><span class="p">[</span><span class="n">row</span><span class="w"> </span><span class="p">(</span><span class="nb">range</span><span class="w"> </span><span class="mi">8</span><span class="p">)</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="p">(</span><span class="nb">range</span><span class="w"> </span><span class="mi">8</span><span class="p">)]</span><span class="w">
                                  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">cell-color</span><span class="w"> </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">zero?</span><span class="w"> </span><span class="p">(</span><span class="nf">mod</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="p">(</span><span class="nf">mod</span><span class="w"> </span><span class="n">row</span><span class="w"> </span><span class="mi">2</span><span class="p">))</span><span class="w"> </span><span class="mi">2</span><span class="p">))</span><span class="w"> </span><span class="s">"#f0d9b5"</span><span class="w"> </span><span class="s">"#b58863"</span><span class="p">)</span><span class="w">
                                        </span><span class="p">{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">kind</span><span class="w"> </span><span class="n">player</span><span class="p">]}</span><span class="w"> </span><span class="p">(</span><span class="nf">pos-&gt;piece</span><span class="w"> </span><span class="p">[</span><span class="n">row</span><span class="w"> </span><span class="n">col</span><span class="p">])</span><span class="w">
                                        </span><span class="n">cell-str</span><span class="w"> </span><span class="p">(</span><span class="nf">kind-&gt;sprite</span><span class="w"> </span><span class="n">kind</span><span class="w"> </span><span class="s">""</span><span class="p">)</span><span class="w">
                                        </span><span class="n">player-color</span><span class="w"> </span><span class="p">(</span><span class="nb">when</span><span class="w"> </span><span class="n">player</span><span class="w"> </span><span class="p">(</span><span class="nb">name</span><span class="w"> </span><span class="n">player</span><span class="p">))]</span><span class="w">
                                    </span><span class="p">(</span><span class="nf">.add</span><span class="w"> </span><span class="n">gp</span><span class="w"> </span><span class="p">(</span><span class="nb">doto</span><span class="w"> </span><span class="p">(</span><span class="nf">Label.</span><span class="w"> </span><span class="n">cell-str</span><span class="p">)</span><span class="w">
                                               </span><span class="p">(</span><span class="nf">.setStyle</span><span class="w"> </span><span class="p">(</span><span class="nf">format</span><span class="w"> </span><span class="s">"-fx-background-color:%s; -fx-font-size:40; -fx-text-fill:%s; -fx-alignment: center;"</span><span class="w">
                                                                  </span><span class="n">cell-color</span><span class="w"> </span><span class="n">player-color</span><span class="p">))</span><span class="w">
                                               </span><span class="p">(</span><span class="nf">.setPrefWidth</span><span class="w"> </span><span class="mi">50</span><span class="p">))</span><span class="w">
                                          </span><span class="p">(</span><span class="nb">int</span><span class="w"> </span><span class="n">col</span><span class="p">)</span><span class="w">
                                          </span><span class="p">(</span><span class="nb">int</span><span class="w"> </span><span class="n">row</span><span class="p">)))))</span><span class="w">
                               </span><span class="n">gp</span><span class="p">)}))})</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_clojurescript_2"><a class="anchor" href="#_clojurescript_2"></a><a class="link" href="#_clojurescript_2">6.9.3. ClojureScript</a></h4>
<div class="paragraph">
<p>Using custom visualizers with ClojureScript (or other remote environments) is a little bit more involved.</p>
</div>
<div class="paragraph">
<p>Registering aspect extractors is exaclty the same, since they run on the runtime (browswer, node, etc), but
custom visualizers should be registered on the debugger process. For this you need to create your visualizers in some
namespace, let&#8217;s say on <code>/dev/visualizers.clj</code>, add the <code>dev</code> folder to your classpath and then running the debugger UI
with something like :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port 9000 :repl-type :shadow :build-id :my-app :pre-require visualizers</code></pre>
</div>
</div>
<div class="paragraph">
<p>Notice the last option <code>:pre-require visualizers</code>. This will allow you to load the just defined <code>visualizers</code> namespace before
starting the UI.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_default_visualizers"><a class="anchor" href="#_default_visualizers"></a><a class="link" href="#_default_visualizers">6.10. Default visualizers</a></h3>
<div class="paragraph">
<p>You can make any visualizer the default by calling <code>add-default-visualizer</code> which takes a predicate on the val-data (the same received by :on-create) and
a visualizer key, like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">viz/add-default-visualizer</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">val-data</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nb">contains?</span><span class="w"> </span><span class="p">(</span><span class="no">:flow-storm.runtime.values/kinds</span><span class="w"> </span><span class="n">val-data</span><span class="p">)</span><span class="w"> </span><span class="no">:chess-board</span><span class="p">))</span><span class="w"> </span><span class="no">:chess-board</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>For all FlowStorm provided visualizers take a look at <code>flow-storm.debugger.ui.data-windows.visualizers</code> namespace.</p>
</div>
<div class="paragraph">
<p>Default visualizers predicates are added in a stack, and tried from the top. This means that you can always overwrite a default by adding a
new one.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_thread_breakpoints"><a class="anchor" href="#_thread_breakpoints"></a><a class="link" href="#_thread_breakpoints">7. Thread breakpoints</a></h2>
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="user_guide_images/thread_breaks.png" alt="thread breaks">
</div>
</div>
<div class="paragraph">
<p><em>FlowStorm</em> is a tracing debugger, which means it can record what is happening without the need of stopping
your programs execution. This is all fine but doesn&#8217;t cover every possible situation. There are
cases where recording everything is impractical, and even if you can start/stop recording whenever you want,
being able to automatically stop your threads at certain points is useful.</p>
</div>
<div class="paragraph">
<p>For these cases, <em>FlowStorm</em> has the ability to set thread breakpoints, which means to define points (functions)
in the execution of your program where you want your threads to wait.
While the threads are waiting you can explore what happened so far.</p>
</div>
<div class="paragraph">
<p>As soon as a thread hits a break function, if recording is on, it will be blocked, and a "Threads blocked" menu will show up in the UI.
You can use this menu to unblock different threads.</p>
</div>
<div class="paragraph">
<p>Once you are done, you can pause recording using the pause button in the main toolbar and un-block every thread.</p>
</div>
<div class="paragraph">
<p>You can define thread breakpoints in two ways :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Using the browser (like in the image below), you can navigate to any function and click on the <code>Break</code> button. This will block the calling
thread every time the selected function gets called.</p>
</li>
<li>
<p>Or you can also install a break by calling (flow-storm.api/break-at 'my-proj.core/some-fn)</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/browser_breakpoints.png" alt="browser breakpoints">
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Conditional threads breakpoints</div>
<div class="paragraph">
<p>The break-at fn accepts a second argument where you can provide a predicate that will be called with the same arguments
of the function you are breaking. It will only break when the predicate returns true. If you don&#8217;t
provide a predicate it will default to <code>(constantly true)</code></p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>You can remove breakpoints by :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Clicking on the browser instrumentation list delete buttons</p>
</li>
<li>
<p>Calling <code>flow-storm.api/remove-break</code> to remove a single breakpoint</p>
</li>
<li>
<p>Calling <code>flow-storm.api/clear-breaks</code> to remove all breakpoints</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_programmable_debugging"><a class="anchor" href="#_programmable_debugging"></a><a class="link" href="#_programmable_debugging">8. Programmable debugging</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p><em>FlowStorm</em> gives you full access to its internal indexes from the repl in Clojure and ClojureScript.
These allows you to explore your recordings using Clojure and write small programs to analyze
them if what&#8217;s provided by the GUI is not enough.</p>
</div>
<div class="paragraph">
<p>Most of what is documented here is also documented in the <code>flow-storm.runtime.indexes.api</code> namespace docstring, which
you can retrieve by evaluating <code>(doc flow-storm.runtime.indexes.api)</code>. In fact, this is the only namespace you need to
require on your repl in order to work with your recordings.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s say you have recorded some execution and now you want to work with the recordings from the repl.</p>
</div>
<div class="paragraph">
<p>So first we require the api ns as <code>ia</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">require</span><span class="w"> </span><span class="o">'</span><span class="p">[</span><span class="n">flow-storm.runtime.indexes.api</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">ia</span><span class="p">])</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Now from the UI, you can get the thread-id of your recordings (the number next to the thread name)
which you will need for accessing them from the repl.</p>
</div>
<div class="sect2">
<h3 id="_timelines"><a class="anchor" href="#_timelines"></a><a class="link" href="#_timelines">8.1. Timelines</a></h3>
<div class="paragraph">
<p>Let&#8217;s say you want to explore recordings on thread 32. You can retrieve its timeline by calling <code>ia/get-timeline</code> like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">timeline</span><span class="w"> </span><span class="p">(</span><span class="nf">ia/get-timeline</span><span class="w"> </span><span class="mi">32</span><span class="p">))</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Once you have the timeline you can start exploring it.</p>
</div>
<div class="paragraph">
<p>The timeline implements many of the Clojure basic interfaces, so you can :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="n">timeline</span><span class="p">)</span><span class="w">
</span><span class="mi">798</span><span class="w">

</span><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="nb">take</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="n">timeline</span><span class="p">)</span><span class="w">
</span><span class="c1">; (#flow-storm/fn-call-trace [Idx: 0 org.my-app/run-server]</span><span class="w">
</span><span class="c1">;  #flow-storm/fn-call-trace [Idx: 1 org.my-app/read-config]</span><span class="w">
</span><span class="c1">;  #flow-storm/fn-call-trace [Idx: 2 org.my-app/check-config])</span><span class="w">

</span><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="nb">get</span><span class="w"> </span><span class="n">timeline</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span><span class="c1">; #flow-storm/fn-call-trace [Idx: 0 org.my-app/run-server]</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The easiest way to take a look at a thread timeline is with some code like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">timeline</span><span class="w">
     </span><span class="p">(</span><span class="nb">take</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w">
     </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="n">ia/as-immutable</span><span class="p">))</span><span class="w">

</span><span class="c1">; ({:type :fn-call,</span><span class="w">
</span><span class="c1">;   :fn-ns "org.my-app",</span><span class="w">
</span><span class="c1">;   :fn-name "run-server",</span><span class="w">
</span><span class="c1">;   :ret-idx 797,</span><span class="w">
</span><span class="c1">;   :fn-call-idx 0,</span><span class="w">
</span><span class="c1">;   :parent-idx nil,</span><span class="w">
</span><span class="c1">;   :fn-args [],</span><span class="w">
</span><span class="c1">;   :form-id -798068730,</span><span class="w">
</span><span class="c1">;   :idx 0}</span><span class="w">
</span><span class="c1">;  ...</span><span class="w">
</span><span class="c1">;  ...)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>In most cases converting all entries into maps with <code>ia/as-immutable</code> is enough, but if you want a little bit more
performance you can access entries information without creating a immutable map first.</p>
</div>
<div class="paragraph">
<p>Timelines entries are of 4 different kinds: <code>FnCallTrace</code>, <code>FnReturnTrace</code>, <code>FnUnwindTrace</code> and <code>ExprTrace</code>.</p>
</div>
<div class="paragraph">
<p>You can access their data by using the following functions depending on the entry :</p>
</div>
<div class="paragraph">
<p>All kinds :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>as-immutable</code></p>
</li>
<li>
<p><code>fn-call-idx</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>ExprTrace</code>, <code>FnReturnTrace</code> and <code>FnUnwindTrace</code> :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>get-coord-vec</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>ExprTrace</code>, <code>FnReturnTrace</code> :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>get-expr-val</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>FnUnwindTrace</code> :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>get-throwable</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>FnCallTrace</code> :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>get-fn-name</code></p>
</li>
<li>
<p><code>get-fn-ns</code></p>
</li>
<li>
<p><code>get-fn-args</code></p>
</li>
<li>
<p><code>get-fn-parent-idx</code></p>
</li>
<li>
<p><code>get-fn-ret-idx</code></p>
</li>
<li>
<p><code>get-fn-bindings</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You can also access the timeline as a tree by calling :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>callstack-root-node</code></p>
</li>
<li>
<p><code>callstack-node-childs</code></p>
</li>
<li>
<p><code>callstack-node-frame-data</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Take a look at their docstrings for more info.</p>
</div>
</div>
<div class="sect2">
<h3 id="_forms"><a class="anchor" href="#_forms"></a><a class="link" href="#_forms">8.2. Forms</a></h3>
<div class="paragraph">
<p>You can retrieve forms by form id with <code>get-form</code> and then use <code>get-sub-form-at-coord</code> and a coordinate.</p>
</div>
<div class="paragraph">
<p>Here is a little example :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="c1">;; retrieve some expression entry into expr</span><span class="w">
</span><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">expr</span><span class="w"> </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="n">timeline</span><span class="w">
                    </span><span class="p">(</span><span class="nb">get</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w">
                    </span><span class="n">ia/as-immutable</span><span class="p">))</span><span class="w">

</span><span class="n">user&gt;</span><span class="w"> </span><span class="n">expr</span><span class="w">
</span><span class="p">{</span><span class="no">:type</span><span class="w"> </span><span class="no">:expr,</span><span class="w"> </span><span class="no">:coord</span><span class="w"> </span><span class="p">[</span><span class="mi">2</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">1</span><span class="p">]</span><span class="n">,</span><span class="w"> </span><span class="no">:result</span><span class="w"> </span><span class="mi">4</span><span class="n">,</span><span class="w"> </span><span class="no">:fn-call-idx</span><span class="w"> </span><span class="mi">2</span><span class="n">,</span><span class="w"> </span><span class="no">:idx</span><span class="w"> </span><span class="mi">3</span><span class="p">}</span><span class="w">

</span><span class="c1">;; retrieve the fn-call entry for our expr</span><span class="w">
</span><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">fn-call</span><span class="w"> </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="n">timeline</span><span class="w">
                       </span><span class="p">(</span><span class="nb">get</span><span class="w"> </span><span class="p">(</span><span class="no">:fn-call-idx</span><span class="w"> </span><span class="n">expr</span><span class="p">))</span><span class="w">
                       </span><span class="n">ia/as-immutable</span><span class="p">))</span><span class="w">
</span><span class="n">user&gt;</span><span class="w"> </span><span class="n">fn-call</span><span class="w">
</span><span class="p">{</span><span class="no">:type</span><span class="w"> </span><span class="no">:fn-call,</span><span class="w">
 </span><span class="no">:fn-ns</span><span class="w"> </span><span class="s">"dev-tester"</span><span class="w">
 </span><span class="no">:fn-name</span><span class="w"> </span><span class="s">"other-function"</span><span class="n">,</span><span class="w">
 </span><span class="no">:form-id</span><span class="w"> </span><span class="mi">1451539897</span><span class="n">,</span><span class="w">
 </span><span class="n">...</span><span class="p">}</span><span class="w">

</span><span class="c1">;; grab it's form</span><span class="w">
</span><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">form</span><span class="w"> </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="n">fn-call</span><span class="w">
                    </span><span class="no">:form-id</span><span class="w">
                    </span><span class="n">ia/get-form</span><span class="w">
                    </span><span class="no">:form/form</span><span class="p">))</span><span class="w">
</span><span class="n">user&gt;</span><span class="w"> </span><span class="n">form</span><span class="w">
</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">other-function</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="mi">10</span><span class="p">)))</span><span class="w">

</span><span class="c1">;; lets look at the sub-form from form at our expr coordinate</span><span class="w">
</span><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">ia/get-sub-form-at-coord</span><span class="w"> </span><span class="n">form</span><span class="w"> </span><span class="p">(</span><span class="no">:coord</span><span class="w"> </span><span class="n">expr</span><span class="p">))</span><span class="w">
</span><span class="n">a</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_multi_thread_timeline_2"><a class="anchor" href="#_multi_thread_timeline_2"></a><a class="link" href="#_multi_thread_timeline_2">8.3. Multi-thread timeline</a></h3>
<div class="paragraph">
<p>If you have recorded a multi-thread timeline, you can retrieve it with <code>total-order-timeline</code> like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">mt-timeline</span><span class="w"> </span><span class="p">(</span><span class="nf">ia/total-order-timeline</span><span class="p">))</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>which you can then iterate using normal Clojure functions (map, filter, reduce, get, etc).</p>
</div>
<div class="paragraph">
<p>The easiest way to explore it is again with some code like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">-&gt;&gt;</span><span class="w"> </span><span class="n">mt-timeline</span><span class="w">
           </span><span class="p">(</span><span class="nb">take</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w">
           </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="n">ia/as-immutable</span><span class="p">))</span><span class="w">

</span><span class="p">({</span><span class="no">:thread-id</span><span class="w"> </span><span class="mi">32</span><span class="n">,</span><span class="w">
  </span><span class="no">:type</span><span class="w"> </span><span class="no">:fn-call,</span><span class="w">
  </span><span class="no">:fn-call-idx</span><span class="w"> </span><span class="mi">0</span><span class="n">,</span><span class="w">
  </span><span class="no">:fn-ns</span><span class="w"> </span><span class="s">"org.my-app"</span><span class="n">,</span><span class="w">
  </span><span class="no">:fn-name</span><span class="w"> </span><span class="s">"run"</span><span class="n">,</span><span class="w">
  </span><span class="no">:fn-args</span><span class="w"> </span><span class="p">[]</span><span class="n">,</span><span class="w">
  </span><span class="no">:ret-idx</span><span class="w"> </span><span class="mi">797</span><span class="n">,</span><span class="w">
  </span><span class="no">:parent-idx</span><span class="w"> </span><span class="n">nil,</span><span class="w">
  </span><span class="no">:form-id</span><span class="w"> </span><span class="mi">-798068730</span><span class="n">,</span><span class="w">
  </span><span class="no">:idx</span><span class="w"> </span><span class="mi">0</span><span class="p">}</span><span class="w">
  </span><span class="n">...</span><span class="w">
  </span><span class="n">...</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Notice that each of these entries contains a flow-id and thread-id also.</p>
</div>
</div>
<div class="sect2">
<h3 id="_other_utilities"><a class="anchor" href="#_other_utilities"></a><a class="link" href="#_other_utilities">8.4. Other utilities</a></h3>
<div class="paragraph">
<p>There are other utitities in the api ns that could be useful, some of the most interesting ones :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>find-expr-entry</code> useful for searching expressions and return values with different criteria.</p>
</li>
<li>
<p><code>find-fn-call-entry</code> useful for searching functions calls with different criteria.</p>
</li>
<li>
<p><code>stack-for-frame</code></p>
</li>
<li>
<p><code>fn-call-stats</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Take a look at their docstrings for more info.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_llm_agents"><a class="anchor" href="#_llm_agents"></a><a class="link" href="#_llm_agents">9. LLM agents</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>You can teach a LLM how to use FlowStorm&#8217;s api to help you analyze your recordings.</p>
</div>
<div class="paragraph">
<p>If you are using the amazing <a href="https://github.com/bhauman/clojure-mcp">clojure-mcp</a> you just need to upload
<a href="https://github.com/flow-storm/flow-storm-debugger/blob/master/llm-prompt.txt">one more file</a> that teaches the LLM FlowStorm&#8217;s basics from the repl.</p>
</div>
<div class="paragraph">
<p><a href="https://claude.ai/share/489c9124-b1a8-4a33-b50a-52e4f3d4709f">Here</a> is a very basic chat asking Claude to look at some recordings of a buggy
TODO&#8217;s web application.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_remote_debugging"><a class="anchor" href="#_remote_debugging"></a><a class="link" href="#_remote_debugging">10. Remote debugging</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>You can remotely debug any Clojure application that exposes a nrepl server.</p>
</div>
<div class="paragraph">
<p>In terms of dependencies, the debuggee side should be setup the same as a normal local setup, with the optional change that you can use
<code>flow-storm-inst</code> instead of <code>flow-storm-dbg</code>, being the former a slimmed down version of the later one that
doesn&#8217;t contain some libraries used only by the UI, but using the full <code>flow-storm-dbg</code> is also ok.</p>
</div>
<div class="sect2">
<h3 id="_ssh_tunnel"><a class="anchor" href="#_ssh_tunnel"></a><a class="link" href="#_ssh_tunnel">10.1. SSH tunnel</a></h3>
<div class="paragraph">
<p>The easiest way to debug a remote application is via a ssh tunnel. You can create it from your dev box like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">ssh <span class="nt">-L</span> 9000:localhost:9000 <span class="nt">-R</span> 7722:localhost:7722 my-debuggee-box.com</code></pre>
</div>
</div>
<div class="paragraph">
<p>assuming your remote process at my-debuggee-box.com has started a nrepl server listening on port 9000 and
that the debugger websocket server is running on the default port.</p>
</div>
<div class="paragraph">
<p>After the tunnel is established, you can run you debugger UI like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port 9000</code></pre>
</div>
</div>
<div class="paragraph">
<p>and that is it.</p>
</div>
<div class="paragraph">
<p>If you need to connect the debugger to a remote process without a ssh tunnel or you need to configure the websocket server port you can do it like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port NREPL-PORT :runtime-host <span class="s1">'"YOUR-APP-BOX-IP-ADDRESS"'</span> :debugger-host <span class="s1">'"YOUR-BOX-IP-ADDRESS"'</span> :ws-port WS-SERVER-PORT</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_out_of_process"><a class="anchor" href="#_out_of_process"></a><a class="link" href="#_out_of_process">10.2. Out of process</a></h3>
<div class="paragraph">
<p>Sometimes you are not debugging across a network but you want to run the FlowStorm UI on a different process.</p>
</div>
<div class="paragraph">
<p>A couple of aliases that can help for this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">{</span><span class="no">:aliases</span><span class="w">
 </span><span class="c1">;; for your system process</span><span class="w">
 </span><span class="p">{</span><span class="no">:runtime-storm</span><span class="w"> </span><span class="p">{</span><span class="no">:classpath-overrides</span><span class="w"> </span><span class="p">{</span><span class="n">org.clojure/clojure</span><span class="w"> </span><span class="n">nil</span><span class="p">}</span><span class="w">
                  </span><span class="no">:extra-deps</span><span class="w"> </span><span class="p">{</span><span class="n">com.github.flow-storm/clojure</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"1.12.3-4"</span><span class="p">}</span><span class="w">
                               </span><span class="n">com.github.flow-storm/flow-storm-inst</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">}}}</span><span class="w">
  </span><span class="c1">;; for the FlowStorm GUI process</span><span class="w">
  </span><span class="no">:ui-storm</span><span class="w"> </span><span class="p">{</span><span class="no">:extra-deps</span><span class="w"> </span><span class="p">{</span><span class="n">com.github.flow-storm/flow-storm-dbg</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">}}</span><span class="w">
             </span><span class="no">:exec-fn</span><span class="w"> </span><span class="n">flow-storm.debugger.main/start-debugger</span><span class="w">
             </span><span class="no">:exec-args</span><span class="w"> </span><span class="p">{</span><span class="no">:port</span><span class="w"> </span><span class="mi">7888</span><span class="p">}}}}</span><span class="w"> </span><span class="c1">;; set your nrepl port here!</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>With those aliases you can start your application process by adding <code>:runtime-storm</code> and that is it.</p>
</div>
<div class="paragraph">
<p>To start the FlowStorm UI, go to another terminal and run <code>clj -X:ui-storm</code>.</p>
</div>
</div>
<div class="sect2">
<h3 id="_docker"><a class="anchor" href="#_docker"></a><a class="link" href="#_docker">10.3. Docker</a></h3>
<div class="paragraph">
<p>If you run you process inside a docker container, here is a basic template for using <em>FlowStorm</em> with it
<a href="https://github.com/jpmonettas/docker-flow-storm-basic" class="bare">https://github.com/jpmonettas/docker-flow-storm-basic</a></p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_dealing_with_too_many_traces"><a class="anchor" href="#_dealing_with_too_many_traces"></a><a class="link" href="#_dealing_with_too_many_traces">11. Dealing with too many traces</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>When recording an application&#8217;s execution (specially when using <em>ClojureStorm</em> or <em>ClojureScriptStorm</em>) it could happen
that your process starts running out of heap. This section documents some tools FlowStorm provides to deal with this situations.</p>
</div>
<div class="paragraph">
<p>Most of the time, having the recording paused and just enabling it right before executing the action you are interested in is enough, but
when it isn&#8217;t, here are some other options.</p>
</div>
<div class="sect2">
<h3 id="_fn_call_limits"><a class="anchor" href="#_fn_call_limits"></a><a class="link" href="#_fn_call_limits">11.1. Fn call limits</a></h3>
<div class="paragraph">
<p>A common situation is to see some high frequency functions adding a lot of noise to your recordings. For example a MouseMove event processing
will generate a lot of recordings while you use your app. There are a couple of ways to limit your functions calls by thread. You can identify
this kind of functions with the <a href="#_functions_tool">functions tool</a>.</p>
</div>
<div class="paragraph">
<p>One tool you can use in this situations is the <code>flowstorm.threadFnCallLimits</code> JVM prop.</p>
</div>
<div class="paragraph">
<p>For example, you can add <code>"-Dflowstorm.threadFnCallLimits=org.my-app/fn1:2,org.my-app/fn2:4"</code> so every time the system starts, limits will be set for
<code>org.my-app/fn1</code> and <code>org.my-app/fn2</code>. The number next to them is the limit. When a function reaches the limit <em>FlowStorm</em> will stop recording calls
to it and all the functions down its callstack.</p>
</div>
<div class="paragraph">
<p>You can also modify the limits from your repl, by calling <code>flow-storm.runtime.indexes.api/[add-fn-call-limit|rm-fn-call-limit|get-fn-call-limits]</code>.
In ClojureScript you need to call them via your cljs repl api.</p>
</div>
<div class="paragraph">
<p>These limits are per thread, so when a thread recording is created it will start with the current defined counters, and each time a function gets called
the counter will decrement. When it reaches zero the function and all functions calls under it will stop being recorded.</p>
</div>
<div class="paragraph">
<p>When you clear your threads you are also clearing its limit counters, so next time you record something new counters will be initialized from your
global limits definitions.</p>
</div>
</div>
<div class="sect2">
<h3 id="_trace_and_heap_limits"><a class="anchor" href="#_trace_and_heap_limits"></a><a class="link" href="#_trace_and_heap_limits">11.2. Trace and heap limits</a></h3>
<div class="paragraph">
<p>If you are tracing some code that ends up in a infinite loop the debugger will choke on
too many traces, making everything slow and your only option is probably to restart it.</p>
</div>
<div class="paragraph">
<p>For preventing this, <em>FlowStorm</em> provides a couple of fuse/breakers, on threads trace count and on heap limits.</p>
</div>
<div class="paragraph">
<p>They are off by default but you can enable it from the Config menu.</p>
</div>
<div class="sect3">
<h4 id="_trace_limits"><a class="anchor" href="#_trace_limits"></a><a class="link" href="#_trace_limits">11.2.1. Trace limits</a></h4>
<div class="paragraph">
<p>Let&#8217;s say you added a thread trace limit of 1000. If you now run any code where a thread generates more than a 1000 traces FlowStorm will only
record those first 1000 traces and then discard the rest as if recording is off for that thread, while it will keep recording threads that haven&#8217;t
reached the limit.</p>
</div>
<div class="paragraph">
<p>Your code will continue execution as normal, which you can break using
your normal editor breaking commands if its an infinite loop, but now you have recordings to look at what is going on.</p>
</div>
<div class="paragraph">
<p>You can set a limit of 0 to disable it again.</p>
</div>
<div class="paragraph">
<p>You can set this limits at startup via the JVM options <code>"-Dflowstorm.threadTraceLimit=1000"</code> and
<code>"-Dflowstorm.throwOnLimit=true"</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_heap_limits"><a class="anchor" href="#_heap_limits"></a><a class="link" href="#_heap_limits">11.2.2. Heap limits</a></h4>
<div class="paragraph">
<p>Another option is to automatically stop recording when a certain heap limit in megabytes is reached.</p>
</div>
<div class="paragraph">
<p>This can also be set at startup via the JVM option <code>"-Dflowstorm.heapLimit=1000"</code>, which means stop recording
as soon as we used 1000Mb of heap space.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_dealing_with_mutable_values"><a class="anchor" href="#_dealing_with_mutable_values"></a><a class="link" href="#_dealing_with_mutable_values">12. Dealing with mutable values</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p><em>FlowStorm</em> will retain all values pointers when code executes so you can analyze them later. This works great with immutable values but
when your code uses mutable values like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="p">(</span><span class="nf">java.util.ArrayList.</span><span class="p">)]</span><span class="w">
  </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w">
  </span><span class="p">(</span><span class="nf">.add</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="s">"hello"</span><span class="p">)</span><span class="w">
  </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w">
  </span><span class="p">(</span><span class="nf">.add</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="s">"world"</span><span class="p">)</span><span class="w">
  </span><span class="p">(</span><span class="nf">.add</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="s">"!"</span><span class="p">))</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>then every time you step over <code>a</code> it will contain the last value ["hello" "world" "!"].</p>
</div>
<div class="paragraph">
<p>You can fix this situation by extending the flow-storm.runtime.values/SnapshotP protocol like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">extend-protocol</span><span class="w"> </span><span class="n">flow-storm.runtime.values/SnapshotP</span><span class="w">
  </span><span class="n">java.util.ArrayList</span><span class="w">
  </span><span class="p">(</span><span class="nf">snapshot-value</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nb">into</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="n">a</span><span class="p">)))</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>to provide <em>FlowStorm</em> a way of creating a snapshot of the mutable value.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">ClojureStorm</div>
<div class="paragraph">
<p>If you are using <em>ClojureStorm</em> evaluate the previous defmethod in a ns that is not being
instrumented to avoid an infinite recursion.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Be aware that this is tricky in multithreading situations, as always with mutable values.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Automatic derefing</div>
<div class="paragraph">
<p>FlowStorm will automatically deref Atoms, Refs, Agents, Vars and all pending-realized derefables on tracing
so no need to implement <code>flow-storm.runtime.values/snapshot-value</code> for them.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Snapshoting and nested values</div>
<div class="paragraph">
<p>Snapshoting only applies to direct references to mutable values.
For example if you have an atom inside a nested immutable collection, it will not be snapshoted every time
that collection expression is being recorded, because the value being recorded is not a reference to an atom.</p>
</div>
<div class="paragraph">
<p>If this is important to you, you can still define snapshot-value for clojure.lang.PersistentArrayMap, etc, and
walk it down snapshoting everything mutable inside.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">snapshot-value and memory footprint</div>
<div class="paragraph">
<p>Although snapshot-value was created as a way to deal with mutable values it can be used to replace any value by another in the
recordings, which can be useful in other situations like reducing memory footprint when you don&#8217;t need the entire
value to be recorded.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_controlling_instrumentation"><a class="anchor" href="#_controlling_instrumentation"></a><a class="link" href="#_controlling_instrumentation">13. Controlling instrumentation</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>If you are using <em>ClojureStorm</em> or <em>ClojureScriptStorm</em> it is important to learn how to control what gets instrumented and
how to uninstrument things. You can configure what gets instrumented automatically on startup via JVM properties but also
change this while your repl is running without the need to restart it.</p>
</div>
<div class="paragraph">
<p>FlowStorm by default will automatically figure out what to instrument from your project, which
you can always disable by setting the <code>-Dclojure.storm.instrumentAutoPrefixes=false</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">How are auto prefixes calculated?</div>
<div class="paragraph">
<p>When the process starts it will scan all source folders on the classpath (everything not inside a jar containing clojure files) and build
a set of all top level namespace. All namespaces under those will be instrumented.
Currently it doesn&#8217;t detect single level namespaces, like when you have <code>src/core.clj</code>, if this is your case use
instrumentOnlyPrefixes.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If you prefer to be explicit about what gets instrumented you can use the JVM property <code>"-Dclojure.storm.instrumentOnlyPrefixes=YOUR_INSTRUMENTATION_STRING"</code></p>
</div>
<div class="paragraph">
<p>where <code>YOUR_INSTRUMENTATION_STRING</code> should be a comma separated list of namespaces prefixes like :</p>
</div>
<div class="literalblock">
<div class="content">
<pre>my-project.,lib1.,lib2.core</pre>
</div>
</div>
<div class="paragraph">
<p>which means automatically instrument my-project.* (which includes all sub namespaces), all lib1.* and only everything under lib2.core</p>
</div>
<div class="paragraph">
<p>All this can be changed after without restarting your repl from <a href="#_modifying_instrumentation_with_the_browser">FlowStorm browser</a>.</p>
</div>
<div class="sect2">
<h3 id="_turning_instrumentation_on_an_off"><a class="anchor" href="#_turning_instrumentation_on_an_off"></a><a class="link" href="#_turning_instrumentation_on_an_off">13.1. Turning instrumentation on an off</a></h3>
<div class="paragraph">
<p>You can turn instrumentation on an off by using the button on <a href="#_the_tool_bar">the toolbar</a>.
Remember that the change of this setting will only be effective on newly compiled code.</p>
</div>
</div>
<div class="sect2">
<h3 id="_setup_startup_instrumentation"><a class="anchor" href="#_setup_startup_instrumentation"></a><a class="link" href="#_setup_startup_instrumentation">13.2. Setup startup instrumentation</a></h3>
<div class="paragraph">
<p>The first important thing is to setup your instrumentation correctly via JVM properties :</p>
</div>
<div class="paragraph">
<p>On <em>ClojureStorm</em> :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="n">-Dclojure.storm.instrumentOnlyPrefixes=my-app,my-lib</span><span class="w">
</span><span class="n">-Dclojure.storm.instrumentSkipPrefixes=my-app.too-heavy,my-lib.uninteresting</span><span class="w">
</span><span class="n">-Dclojure.storm.instrumentSkipRegex=.*test.*</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>On <em>ClojureScriptStorm</em> :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="n">-Dcljs.storm.instrumentOnlyPrefixes=my-app,my-lib</span><span class="w">
</span><span class="n">-Dcljs.storm.instrumentSkipPrefixes=my-app.too-heavy,my-lib.uninteresting</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Apart from <code>instrumentOnlyPrefixes</code> which you probably already know, there is <code>instrumentSkipPrefixes</code> which also
accepts a comma separated list of namespaces prefixes to skip, and instrumentSkipRegex with accepts a regex for
namespaces to skip. All these together allows you to instrument you whole app but some undesired namespaces.</p>
</div>
<div class="paragraph">
<p>The next important thing is to be able to enable/disable instrumentation and add/remove prefixes without restarting the
repl.</p>
</div>
</div>
<div class="sect2">
<h3 id="_modifying_instrumentation_with_the_browser"><a class="anchor" href="#_modifying_instrumentation_with_the_browser"></a><a class="link" href="#_modifying_instrumentation_with_the_browser">13.3. Modifying instrumentation with the Browser</a></h3>
<div class="paragraph">
<p>You can use the <code>Browser tool</code> to check and change on the fly the prefixes you configured in the previous section.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/browser_storm_instrumentation_1.png" alt="browser storm instrumentation 1">
</div>
</div>
<div class="paragraph">
<p>Right clicking any namespace will give you options for what level of a namespace you want to instrument.</p>
</div>
<div class="paragraph">
<p>On the bottom pane (instrumentations) you will see your current instrumentation configuration (if any). Here we can see that everything under
<code>ring.middleware.anti-forgery</code> will be instrumented every time something inside it gets compiled.</p>
</div>
<div class="paragraph">
<p>You can remove entries using the <code>del</code> buttons or temporarily disable/enable them using the <code>Enable all</code> checkbox.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/browser_storm_instrumentation_2.png" alt="browser storm instrumentation 2">
</div>
</div>
<div class="paragraph">
<p>You can use the <code>Add</code> menu in the picure above to add instrumentation prefixes.</p>
</div>
<div class="paragraph">
<p>After changing any prefix FlowStorm will ask if you want it to reload the affected namespaces for you. Namespace reloading will
all reload all namespaces it depends on in topological order, so it shouldn&#8217;t break your system in any way.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/browser_storm_instrumentation_3.png" alt="browser storm instrumentation 3">
</div>
</div>
<div class="paragraph">
<p>You can also provide functions to be called before and after reloading in case you need to stop and start your system with :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">flow-storm.api/set-before-reload-callback!</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="p">(</span><span class="nb">println</span><span class="w"> </span><span class="s">"Before reloading"</span><span class="p">)))</span><span class="w">
</span><span class="p">(</span><span class="nf">flow-storm.api/set-after-reload-callback!</span><span class="w">  </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="p">(</span><span class="nb">println</span><span class="w"> </span><span class="s">"After reloading"</span><span class="p">)))</span></code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">Instrumentation</div>
<div class="paragraph">
<p>Just changing the prefixes without reloading will not make your currently loaded code [un]instrumented.
If you haven&#8217;t let FlowStorm reload them for you, you can always recompile them as usual with your editor commands or
by executing something like <code>(require 'the-selected.namespace :reload)</code>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_instrumentation_in_vanilla_flowstorm"><a class="anchor" href="#_instrumentation_in_vanilla_flowstorm"></a><a class="link" href="#_instrumentation_in_vanilla_flowstorm">13.4. Instrumentation in Vanilla FlowStorm</a></h3>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="title">ClojureStorm</div>
<div class="paragraph">
<p>Instructions here only apply to vanilla <em>FlowStorm</em>. If you are using <em>ClojureStorm</em> or <em>ClojureScriptStorm</em> (recommended)
this is done automatically for you, so just skip this section.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Code instrumentation in <em>FlowStorm</em> is done by rewriting your code, in a way that doesn&#8217;t change its behavior
but when executed will trace everything the code is doing.</p>
</div>
<div class="sect3">
<h4 id="_instrument_any_form_with_trace"><a class="anchor" href="#_instrument_any_form_with_trace"></a><a class="link" href="#_instrument_any_form_with_trace">13.4.1. Instrument any form with #trace</a></h4>
<div class="paragraph">
<p>You can instrument any top level form at the repl by writing <code>#trace</code> before it, like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="o">#</span><span class="n">trace</span><span class="w">
</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">sum</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="p">))</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>and then evaluating the form.</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">important</dt>
<dd>
<p><code>#trace</code> is meant to be used with forms that don&#8217;t run immediately, like: defn, defmethod, extend-type, etc.
Use <code>#rtrace</code> to trace and run a form, like <code>#rtrace (map inc (range 10))</code>.</p>
</dd>
</dl>
</div>
</div>
<div class="sect3">
<h4 id="_run_code_with_rtrace"><a class="anchor" href="#_run_code_with_rtrace"></a><a class="link" href="#_run_code_with_rtrace">13.4.2. Run code with #rtrace</a></h4>
<div class="paragraph">
<p><code>#rtrace</code> is useful in two situations :</p>
</div>
<div class="paragraph">
<p>First, when instrumenting and running a simple form at the repl, like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="o">#</span><span class="n">rtrace</span><span class="w"> </span><span class="p">(</span><span class="nb">-&gt;</span><span class="w"> </span><span class="p">(</span><span class="nb">range</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">filter</span><span class="w"> </span><span class="n">odd?</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">take</span><span class="w"> </span><span class="mi">10</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="nb">+</span><span class="p">))</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_instrument_namespaces"><a class="anchor" href="#_instrument_namespaces"></a><a class="link" href="#_instrument_namespaces">13.4.3. Instrument namespaces</a></h4>
<div class="paragraph">
<p><em>FlowStorm</em> allows you to instrument entire namespaces by providing <code>flow-storm.api/instrument-namespaces-clj</code>.</p>
</div>
<div class="paragraph">
<p>You call it like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="nf">instrument-namespaces-clj</span><span class="w"> </span><span class="o">#</span><span class="p">{</span><span class="s">"org.my-app.core"</span><span class="w"> </span><span class="s">"cljs."</span><span class="p">})</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The first argument is a set of namespaces prefixes to instrument. In the previous example it means
instrument all namespaces starting with <code>org.my-app.core</code>, and all starting with <code>cljs.</code></p>
</div>
<div class="paragraph">
<p>The second argument can be a map supporting the following options :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>:excluding-ns</code> a set of strings with namespaces that should be excluded</p>
</li>
<li>
<p><code>:disable</code> a set containing any of #{<code>:expr</code> <code>:binding</code> <code>:anonymous-fn</code>} useful for disabling unnecessary traces in code that generate too many</p>
</li>
<li>
<p><code>:verbose?</code> when true show more logging</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_what_cant_be_instrumented"><a class="anchor" href="#_what_cant_be_instrumented"></a><a class="link" href="#_what_cant_be_instrumented">13.4.4. What can&#8217;t be instrumented?</a></h4>
<div class="paragraph">
<p>These are some limitations when instrumenting forms :</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Very big forms can&#8217;t be fully instrumented. The JVM spec has a limit on the size of methods and instrumentation adds a lot of code.
When instrumenting entire namespaces, if you hit this limit on a form a warning will printed on the console saying <code>Instrumented expression is too large for the Clojure compiler</code>
and <em>FlowStorm</em> automatically tries to instrument it with a lighter profile, by disabling some instrumentation.</p>
</li>
<li>
<p>Functions that call recur without a loop</p>
</li>
<li>
<p>Functions that return recursive lazy sequences. Like <code>(fn foo [] (lazy-seq (&#8230;&#8203; (foo))))</code></p>
</li>
</ol>
</div>
</div>
<div class="sect3">
<h4 id="_un_instrument_code"><a class="anchor" href="#_un_instrument_code"></a><a class="link" href="#_un_instrument_code">13.4.5. Un-instrument code</a></h4>
<div class="paragraph">
<p>Un-instrumenting code that has been instrumented with <code>#trace</code> or <code>#ctrace</code> is straight forward, just remove the tag and re evaluate the form.</p>
</div>
<div class="paragraph">
<p>To un-instrument entire namespaces you can use <code>flow-storm.api/uninstrument-namespaces-clj</code> which accept a set of namespaces prefixes.</p>
</div>
</div>
<div class="sect3">
<h4 id="_instrument_with_the_browser"><a class="anchor" href="#_instrument_with_the_browser"></a><a class="link" href="#_instrument_with_the_browser">13.4.6. Instrument with the browser</a></h4>
<div class="paragraph">
<p>Most of the time you can instrument code by just clicking in the browser. The only exceptions are functions that were just defined in the repl
and weren&#8217;t loaded from a file.</p>
</div>
<div class="sect4">
<h5 id="_instrument_vars"><a class="anchor" href="#_instrument_vars"></a><a class="link" href="#_instrument_vars">Instrument vars</a></h5>
<div class="paragraph">
<p>Using the browser you can navigate to the var you are interested in and then use the instrument button to instrument it.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/browser_var_instrumentation.png" alt="browser var instrumentation">
</div>
</div>
<div class="paragraph">
<p>There are two ways of instrumenting a var :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Instrument (instrument just the var source code)</p>
</li>
<li>
<p>Instrument recursively (recursively instrument the var and all vars referred by it)</p>
</li>
</ul>
</div>
</div>
<div class="sect4">
<h5 id="_instrument_namespaces_2"><a class="anchor" href="#_instrument_namespaces_2"></a><a class="link" href="#_instrument_namespaces_2">Instrument namespaces</a></h5>
<div class="paragraph">
<p>Using the browser you can also instrument multiple namespaces. Do this by selecting the namespaces you are interested in
and then a right click should show you a menu with two instrumentation commands.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/browser_ns_instrumentation.png" alt="browser ns instrumentation">
</div>
</div>
<div class="ulist">
<ul>
<li>
<p><code>Instrument namespace :light</code> - record function arguments and return values (not expressions, no bindings tracing)</p>
</li>
<li>
<p><code>Instrument namespace :full</code> fully instrument everything</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Light instrumentation is useful when you know the functions generate too many traces, so you can opt to trace just functions
calls and returns. You can then <a href="#_fully_instrument_a_form_from_the_code_view">fully instrument</a> whatever functions you are interested in.</p>
</div>
</div>
<div class="sect4">
<h5 id="_un_instrument_code_2"><a class="anchor" href="#_un_instrument_code_2"></a><a class="link" href="#_un_instrument_code_2">Un-instrument code</a></h5>
<div class="paragraph">
<p>The bottom panel shows all instrumented vars and namespaces.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/browser_uninstrument.png" alt="browser uninstrument">
</div>
</div>
<div class="paragraph">
<p>You can un-instrument them temporarily with the enable/disable checkbox or
permanently with the del button.</p>
</div>
</div>
<div class="sect4">
<h5 id="_fully_instrument_a_form_from_the_code_view"><a class="anchor" href="#_fully_instrument_a_form_from_the_code_view"></a><a class="link" href="#_fully_instrument_a_form_from_the_code_view">Fully instrument a form from the code view</a></h5>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/fully_instrument_form.png" alt="fully instrument form">
</div>
</div>
<div class="paragraph">
<p>If you have instrumented a form with the <a href="#_instrument_namespaces_2">:light profile</a> you can fully instrument it by right clicking on the current form
and then clicking <code>Fully instrument this form</code>.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_plugins"><a class="anchor" href="#_plugins"></a><a class="link" href="#_plugins">14. Plugins</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>FlowStorm plugins allows you to add specialized tools to visualize and interact
with your recordings.</p>
</div>
<div class="sect2">
<h3 id="_using_plugins"><a class="anchor" href="#_using_plugins"></a><a class="link" href="#_using_plugins">14.1. Using plugins</a></h3>
<div class="paragraph">
<p>For using a pluggin follow each plugging instructions which should normally consists of adding
its dependency and then setting the jvm prop <code>flowstorm.plugins.namespaces</code> with all the main
namespaces of the plugins you want loaded at startup, like : <code>"-Dflowstorm.plugins.namespaces=flow-storm.plugins.my-plugin.all"</code></p>
</div>
<div class="paragraph">
<p>After that you should see a new vertical tab with the plugin UI as you can see here :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="user_guide_images/plugin_demo.png" alt="plugin demo">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_creating_plugins"><a class="anchor" href="#_creating_plugins"></a><a class="link" href="#_creating_plugins">14.2. Creating plugins</a></h3>
<div class="paragraph">
<p>Creating a pluging consists of two parts :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The runtime code that will analyze the recordings and expose an api for the UI</p>
</li>
<li>
<p>The UI component which will visualize and interact with the data via the runtime api</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This split is not required, but it is important if you want your plugin to support ClojureScript also or
remote Clojure debugging where the UI is not running in the same process as the runtime.</p>
</div>
<div class="paragraph">
<p>This components are normally split in two files, a runtime.clj and ui.clj, but you can name them however you
want.</p>
</div>
<div class="paragraph">
<p>We are going to go over each part in more detail but for a real plugin please checkout the <a href="https://github.com/flow-storm/flow-storm-async-flow-plugin">core.async.flow plugin</a>.</p>
</div>
<div class="sect3">
<h4 id="_runtime"><a class="anchor" href="#_runtime"></a><a class="link" href="#_runtime">14.2.1. Runtime</a></h4>
<div class="paragraph">
<p>Here is a runtime file template you can use :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">(</span><span class="nf">ns</span><span class="w"> </span><span class="n">flow-storm.plugins.my-plugin.runtime</span><span class="w">
  </span><span class="p">(</span><span class="no">:require</span><span class="w"> </span><span class="p">[</span><span class="n">flow-storm.runtime.indexes.api</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">ia</span><span class="p">]</span><span class="w">
            </span><span class="p">[</span><span class="n">flow-storm.runtime.debuggers-api</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">dbg-api</span><span class="p">]))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">my-data-extraction</span><span class="w"> </span><span class="p">[</span><span class="n">flow-id</span><span class="w"> </span><span class="n">thread-id</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">timeline</span><span class="w"> </span><span class="p">(</span><span class="nf">ia/get-timeline</span><span class="w"> </span><span class="n">flow-id</span><span class="w"> </span><span class="n">thread-id</span><span class="p">)]</span><span class="w">
    </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">acc</span><span class="w"> </span><span class="n">tl-entry</span><span class="p">]</span><span class="w">
              </span><span class="c1">;; extract some interesting info from the timeline</span><span class="w">
              </span><span class="p">)</span><span class="w">
            </span><span class="p">{}</span><span class="w">
            </span><span class="n">timeline</span><span class="p">)</span><span class="w">
    </span><span class="p">))</span><span class="w">

</span><span class="c1">;; Expose your function so it can be called from the UI part</span><span class="w">
</span><span class="p">(</span><span class="nf">dbg-api/register-api-function</span><span class="w"> </span><span class="no">:plugins.my-plugin/extract-data</span><span class="w"> </span><span class="n">my-data-extraction</span><span class="p">)</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_ui"><a class="anchor" href="#_ui"></a><a class="link" href="#_ui">14.2.2. UI</a></h4>
<div class="paragraph">
<p>Here is a ui file template you can use :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="p">(</span><span class="nf">ns</span><span class="w"> </span><span class="n">flow-storm.plugins.my-plugin.ui</span><span class="w">
  </span><span class="p">(</span><span class="no">:require</span><span class="w"> </span><span class="p">[</span><span class="n">flow-storm.debugger.ui.plugins</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">fs-plugins</span><span class="p">]</span><span class="w">
            </span><span class="p">[</span><span class="n">flow-storm.debugger.runtime-api</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">runtime-api</span><span class="w"> </span><span class="no">:refer</span><span class="w"> </span><span class="p">[</span><span class="n">rt-api</span><span class="p">]])</span><span class="w">
  </span><span class="p">(</span><span class="no">:import</span><span class="w"> </span><span class="p">[</span><span class="n">javafx.scene.control</span><span class="w"> </span><span class="n">Label</span><span class="p">]))</span><span class="w">

</span><span class="p">(</span><span class="nf">fs-plugins/register-plugin</span><span class="w">
 </span><span class="no">:my-plugin</span><span class="w">
 </span><span class="p">{</span><span class="no">:label</span><span class="w"> </span><span class="s">"My plugin"</span><span class="w">
  </span><span class="no">:css-resource</span><span class="w">  </span><span class="s">"flow-storm-my-plugin/dark.css"</span><span class="w">
  </span><span class="no">:dark-css-resource</span><span class="w">  </span><span class="s">"flow-storm-my-plugin/dark.css"</span><span class="w">
  </span><span class="no">:light-css-resource</span><span class="w"> </span><span class="s">"flow-storm-my-plugin/light.css"</span><span class="w">
  </span><span class="no">:on-focus</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">some-other-data</span><span class="p">]}]</span><span class="w">
              </span><span class="c1">;; This gets called everytime the plugin tab gets focused</span><span class="w">
              </span><span class="p">)</span><span class="w">
  </span><span class="no">:on-create</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">_</span><span class="p">]</span><span class="w">
               </span><span class="p">{</span><span class="no">:fx/node</span><span class="w"> </span><span class="p">(</span><span class="nf">Label.</span><span class="w">
                          </span><span class="c1">;; You can call your runtime registered function</span><span class="w">
                          </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="p">(</span><span class="nf">runtime-api/call-by-fn-key</span><span class="w"> </span><span class="n">rt-api</span><span class="w"> </span><span class="no">:plugins.my-plugin/extract-data</span><span class="w"> </span><span class="p">[</span><span class="mi">0</span><span class="w"> </span><span class="mi">10</span><span class="p">])))</span><span class="w">
                </span><span class="no">:some-other-data</span><span class="w"> </span><span class="mi">42</span><span class="p">})</span><span class="w">
  </span><span class="no">:on-flow-clear</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">flow-id</span><span class="w"> </span><span class="p">{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">some-other-data</span><span class="p">]}]</span><span class="w">
                     </span><span class="c1">;; this gets called everytime a flow is discarded so you can update your plugin UI accordignly</span><span class="w">
                   </span><span class="p">)</span><span class="w">
  </span><span class="p">})</span></code></pre>
</div>
</div>
<div class="sect4">
<h5 id="_styling_plugins_uis"><a class="anchor" href="#_styling_plugins_uis"></a><a class="link" href="#_styling_plugins_uis">Styling plugins UIs</a></h5>
<div class="paragraph">
<p>As you saw in the ui plugin registration, you can provide three resources related to styling :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>:css-resource If there is any, it will be loaded and applied. Here is where you put your JavaFX pluging styles</p>
</li>
<li>
<p>:dark-css-resource This styles are going to be applied only in dark mode</p>
</li>
<li>
<p>:light-css-resource This styles are going to be applied only in light mode</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For making sure you plugin styles doesn&#8217;t mix with other styles, your plugin is automatically wrapped in a pane
with your plugin key (my-plugin in the example above) as a class.</p>
</div>
<div class="paragraph">
<p>This means your plugin css can contain code like :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight nowrap"><code data-lang="clojure"><span class="n">.my-plugin</span><span class="w"> </span><span class="n">.table-view</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">-fx-font-family</span><span class="err">:</span><span class="w"> </span><span class="ss">'monospaced</span><span class="o">'</span><span class="c1">;</span><span class="w">
</span><span class="p">}</span></code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_list_of_known_plugins"><a class="anchor" href="#_list_of_known_plugins"></a><a class="link" href="#_list_of_known_plugins">14.3. List of known plugins</a></h3>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/flow-storm/flow-storm-web-plugin" class="bare">https://github.com/flow-storm/flow-storm-web-plugin</a></p>
</li>
<li>
<p><a href="https://github.com/flow-storm/flow-storm-flowbook-plugin" class="bare">https://github.com/flow-storm/flow-storm-flowbook-plugin</a></p>
</li>
<li>
<p><a href="https://github.com/flow-storm/flow-storm-cljs-compiler-plugin" class="bare">https://github.com/flow-storm/flow-storm-cljs-compiler-plugin</a></p>
</li>
<li>
<p><a href="https://github.com/flow-storm/flow-storm-async-flow-plugin" class="bare">https://github.com/flow-storm/flow-storm-async-flow-plugin</a></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_jvm_options_list"><a class="anchor" href="#_jvm_options_list"></a><a class="link" href="#_jvm_options_list">15. JVM options list</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>This section only collects the options, search for them in the User&#8217;s guide for more context
and possible values.</p>
</div>
<div class="sect2">
<h3 id="_clojure_and_clojurescript"><a class="anchor" href="#_clojure_and_clojurescript"></a><a class="link" href="#_clojure_and_clojurescript">15.1. Clojure and ClojureScript</a></h3>
<div class="ulist">
<ul>
<li>
<p><code>-Dflowstorm.startRecording=false</code></p>
</li>
<li>
<p><code>-Dflowstorm.plugins.namespaces[.+]=ns1,ns2</code></p>
</li>
<li>
<p><code>-Dflowstorm.threadFnCallLimits=org.my-app/fn1:2,org.my-app/fn2:4</code></p>
</li>
<li>
<p><code>-Dflowstorm.title=FlowStormMainDebugger</code></p>
</li>
<li>
<p><code>-Dflowstorm.theme=dark</code></p>
</li>
<li>
<p><code>-Dflowstorm.styles=~/.flow-storm/big-fonts.css</code></p>
</li>
<li>
<p><code>-Dflowstorm.fileEditorCommand=emacsclient -n +&lt;&lt;LINE&gt;&gt;:0 &lt;&lt;FILE&gt;&gt;</code></p>
</li>
<li>
<p><code>-Dflowstorm.jarEditorCommand=emacsclient -n +&lt;&lt;LINE&gt;&gt;:0 &lt;&lt;JAR&gt;&gt;/&lt;&lt;FILE&gt;&gt;</code></p>
</li>
<li>
<p><code>-Dflowstorm.threadTraceLimit=1000</code></p>
</li>
<li>
<p><code>-Dflowstorm.throwOnLimit=true</code></p>
</li>
<li>
<p><code>-Dflowstorm.autoUpdateUI=false</code></p>
</li>
<li>
<p><code>-Dflowstorm.callTreeUpdate=false</code></p>
</li>
<li>
<p><code>-Dflowstorm.uiTimeoutMillis=4000</code></p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_only_clojure"><a class="anchor" href="#_only_clojure"></a><a class="link" href="#_only_clojure">15.2. Only Clojure</a></h3>
<div class="ulist">
<ul>
<li>
<p><code>-Dclojure.storm.instrumentEnable=true</code></p>
</li>
<li>
<p><code>-Dclojure.storm.instrumentOnlyPrefixes[.*]=ns-prefix1,ns-prefix2</code></p>
</li>
<li>
<p><code>-Dclojure.storm.instrumentAutoPrefixes=false</code></p>
</li>
<li>
<p><code>-Dclojure.storm.instrumentSkipPrefixes[.*]=my-app.too-heavy,my-lib.uninteresting</code></p>
</li>
<li>
<p><code>-Dclojure.storm.instrumentSkipRegex=.*test.*</code></p>
</li>
<li>
<p><code>-Dflowstorm.heapLimit=1000</code></p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_only_clojurescript"><a class="anchor" href="#_only_clojurescript"></a><a class="link" href="#_only_clojurescript">15.3. Only ClojureScript</a></h3>
<div class="ulist">
<ul>
<li>
<p><code>-Dcljs.storm.instrumentEnable=true</code></p>
</li>
<li>
<p><code>-Dcljs.storm.instrumentOnlyPrefixes=ns-prefix1,ns-prefix2</code></p>
</li>
<li>
<p><code>-Dcljs.storm.instrumentAutoPrefixes=false</code></p>
</li>
<li>
<p><code>-Dcljs.storm.instrumentOnlyPrefixes=my-app,my-lib</code></p>
</li>
<li>
<p><code>-Dcljs.storm.instrumentSkipPrefixes=my-app.too-heavy,my-lib.uninteresting</code></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_styling_and_theming"><a class="anchor" href="#_styling_and_theming"></a><a class="link" href="#_styling_and_theming">16. Styling and theming</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>All functions that start the debugger ui (<code>flow-storm.api/local-connect</code>, <code>flow-storm.debugger.main/start-debugger</code>) accept a map
with the <code>:styles</code>, <code>:title</code> and <code>:theme</code> keywords. If <code>:styles</code> points to a css file it will be used to overwrite the default styles, in case you
want to change colors, make your fonts bigger, etc. <code>:theme</code> could be one of <code>:auto</code> (default), <code>:light</code>, <code>:dark</code>. Title can be used to
distinguish between multiple debugger instances.</p>
</div>
<div class="paragraph">
<p>Like this :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="n">user&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">local-connect</span><span class="w"> </span><span class="p">{</span><span class="no">:styles</span><span class="w"> </span><span class="s">"~/.flow-storm/big-fonts.css"</span><span class="n">,</span><span class="w"> </span><span class="no">:theme</span><span class="w"> </span><span class="no">:dark,</span><span class="w"> </span><span class="no">:title</span><span class="w"> </span><span class="s">"FlowStormMainDebugger"</span><span class="p">})</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>If you are using <em>ClojureStorm</em> you can also provide them with :</p>
</div>
<div class="literalblock">
<div class="content">
<pre>-Dflowstorm.title=FlowStormMainDebugger
-Dflowstorm.theme=dark
-Dflowstorm.styles=~/.flow-storm/big-fonts.css</pre>
</div>
</div>
<div class="paragraph">
<p>You can overwrite all the styles defined here <a href="https://github.com/flow-storm/flow-storm-debugger/blob/master/resources/flowstorm/styles/styles.css" class="bare">https://github.com/flow-storm/flow-storm-debugger/blob/master/resources/flowstorm/styles/styles.css</a></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_controlling_logging"><a class="anchor" href="#_controlling_logging"></a><a class="link" href="#_controlling_logging">17. Controlling logging</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>FlowStorm uses JUL (java.util.logging) as the loggging library.</p>
</div>
<div class="paragraph">
<p>You can configure JUL logging by starting your repl with <code>-Djava.util.logging.config.file=./logging.properties</code></p>
</div>
<div class="paragraph">
<p>If you need to disable logging you can put this in your <code>logging.properties</code> file :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="text">handlers = java.util.logging.ConsoleHandler

flow_storm.level = SEVERE
clojure.storm.level = SEVERE</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_key_bindings"><a class="anchor" href="#_key_bindings"></a><a class="link" href="#_key_bindings">18. Key bindings</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_general"><a class="anchor" href="#_general"></a><a class="link" href="#_general">18.1. General</a></h3>
<div class="ulist">
<ul>
<li>
<p><code>Ctrl-g</code> Cancel any long running task (only search supported yet)</p>
</li>
<li>
<p><code>Ctrl-l</code> Clean all debugger state</p>
</li>
<li>
<p><code>Ctrl-d</code> Toggle debug-mode. Will log useful debugging information to the console</p>
</li>
<li>
<p><code>Ctrl-u</code> Unblock all breakpoint blocked threads if any</p>
</li>
<li>
<p><code>Ctrl-t</code> Rotate themes</p>
</li>
<li>
<p><code>Ctrl-plus</code> Increment font size</p>
</li>
<li>
<p><code>Ctrl-minus</code> Decrement font size</p>
</li>
<li>
<p><code>F</code>      "Select the Flows tool"</p>
</li>
<li>
<p><code>B</code>      "Select the Browser tool"</p>
</li>
<li>
<p><code>T</code>      "Select the Taps tool"</p>
</li>
<li>
<p><code>D</code>      "Select the Docs tool"</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_flows"><a class="anchor" href="#_flows"></a><a class="link" href="#_flows">18.2. Flows</a></h3>
<div class="ulist">
<ul>
<li>
<p><code>0-9</code> Open focus flow-N threads menu, N being the pressed key</p>
</li>
<li>
<p><code>t</code> Select the tree tool (needs to be inside a thread)</p>
</li>
<li>
<p><code>c</code> Select the code tool (needs to be inside a thread)</p>
</li>
<li>
<p><code>f</code> Select the functions tool (needs to be inside a thread)</p>
</li>
<li>
<p><code>P</code> Step prev over. Go to previous step on the same frame</p>
</li>
<li>
<p><code>p</code> Step prev</p>
</li>
<li>
<p><code>n</code> Step next</p>
</li>
<li>
<p><code>N</code> Step next over. Go to next step on the same frame</p>
</li>
<li>
<p><code>^</code> Step out</p>
</li>
<li>
<p><code>&lt;</code> Step first</p>
</li>
<li>
<p><code>&gt;</code> Step last</p>
</li>
<li>
<p><code>Ctrl-f</code> Copy current function symbol</p>
</li>
<li>
<p><code>Ctrl-Shift-f</code> Copy current function call form</p>
</li>
<li>
<p><code>Ctrl-z</code> Undo navigation</p>
</li>
<li>
<p><code>Ctrl-r</code> Redo navigation</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_debugging_react_native_applications"><a class="anchor" href="#_debugging_react_native_applications"></a><a class="link" href="#_debugging_react_native_applications">19. Debugging react native applications</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Debugging ClojureScript react native application needs a combination of ClojureScript and remote debugging.</p>
</div>
<div class="paragraph">
<p>Assuming you are using shadow-cljs, have added the <code>flow-storm-inst</code> dependency, and that it started a nrepl server on port 9000, you
can start a debugger and connect to it by running :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">clj <span class="nt">-Sforce</span> <span class="nt">-Sdeps</span> <span class="s1">'{:deps {com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.9"}}}'</span> <span class="nt">-X</span> flow-storm.debugger.main/start-debugger :port 9000 :repl-type :shadow :build-id :your-app-build-id :debugger-host <span class="s1">'"YOUR_DEV_MACHINE_IP"'</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>You also need to make it possible for the device to connect back to the debugger on port 7722. You can accomplish this by running :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">adb reverse tcp:7722 tcp:7722</code></pre>
</div>
</div>
<div class="paragraph">
<p>Also remember that you need to have installed the <code>websocket</code> npm library. You can do this like :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">npm <span class="nb">install </span>websocket <span class="nt">--save</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_working_on_windows_with_wsl2"><a class="anchor" href="#_working_on_windows_with_wsl2"></a><a class="link" href="#_working_on_windows_with_wsl2">20. Working on Windows with WSL2</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>For those using current versions of WSL2 on Windows it should be pretty straight forward.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>export DISPLAY=:0</p>
</li>
<li>
<p>export WSL2_GUI_APPS_ENABLED=1</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Font issues had been reported on some distros, like <code>java.lang.NullPointerException: Cannot read field "firstFont" because "&lt;local4&gt;" is null</code> which
seams to be solved just by installing font packages like <code>dejavu-fonts</code> or <code>ttf-dejavu</code> depending on the distro.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_opening_forms_in_editors"><a class="anchor" href="#_opening_forms_in_editors"></a><a class="link" href="#_opening_forms_in_editors">21. Opening forms in editors</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>You can add this two jvm options to tell FlowStorm how to open forms in files and inside jars :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>flowstorm.jarEditorCommand : a command with optional &lt;&lt;JAR&gt;&gt;, &lt;&lt;FILE&gt;&gt; and &lt;&lt;LINE&gt;&gt; placeholders</p>
</li>
<li>
<p>flowstorm.fileEditorCommand : a command with optional &lt;&lt;FILE&gt;&gt; and &lt;&lt;LINE&gt;&gt; placeholders</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If you define those, clicking on your forms namespaces link in the code tool should run the provided commands.
On expressions sub-forms that contains line meta you should also be able to right click and select "Open in editor"
which should open the file at that specific line (useful for long forms).</p>
</div>
<div class="paragraph">
<p>Here are some known setups for most common editors :</p>
</div>
<div class="sect2">
<h3 id="_emacs"><a class="anchor" href="#_emacs"></a><a class="link" href="#_emacs">21.1. Emacs</a></h3>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="c1">;; for opening your project files</span><span class="w">
</span><span class="s">"-Dflowstorm.fileEditorCommand=emacsclient -n +&lt;&lt;LINE&gt;&gt;:0 &lt;&lt;FILE&gt;&gt;"</span><span class="w">

</span><span class="c1">;; simple way for opening files inside jars (works on linux only)</span><span class="w">
</span><span class="s">"-Dflowstorm.jarEditorCommand=emacsclient -n +&lt;&lt;LINE&gt;&gt;:0 &lt;&lt;JAR&gt;&gt;/&lt;&lt;FILE&gt;&gt;"</span><span class="w">

</span><span class="c1">;; for opening files inside jars that works on every OS (requires FlowStorm &gt;= 3.17.3)</span><span class="w">
</span><span class="s">"-Dflowstorm.jarEditorCommand=emacsclient --eval '(let ((b (cider-find-file \"jar:file:&lt;&lt;JAR&gt;&gt;!/&lt;&lt;FILE&gt;&gt;\"))) (with-current-buffer b (switch-to-buffer b) (goto-char (point-min)) (forward-line (1- &lt;&lt;LINE&gt;&gt;))))'"</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_vscode"><a class="anchor" href="#_vscode"></a><a class="link" href="#_vscode">21.2. VSCode</a></h3>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="s">"-Dflowstorm.fileEditorCommand=code --goto &lt;&lt;FILE&gt;&gt;:&lt;&lt;LINE&gt;&gt;"</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_intellij"><a class="anchor" href="#_intellij"></a><a class="link" href="#_intellij">21.3. IntelliJ</a></h3>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="s">"-Dflowstorm.fileEditorCommand=idea --line &lt;&lt;LINE&gt;&gt; &lt;&lt;FILE&gt;&gt;"</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_vim"><a class="anchor" href="#_vim"></a><a class="link" href="#_vim">21.4. Vim</a></h3>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="s">"-Dflowstorm.fileEditorCommand=vim +&lt;&lt;LINE&gt;&gt; &lt;&lt;FILE&gt;&gt;"</span></code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_editorsides_integration"><a class="anchor" href="#_editorsides_integration"></a><a class="link" href="#_editorsides_integration">22. Editors/IDEs integration</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_emacs_2"><a class="anchor" href="#_emacs_2"></a><a class="link" href="#_emacs_2">22.1. Emacs</a></h3>
<div class="paragraph">
<p>Checkout <a href="https://github.com/flow-storm/cider-storm">Cider Storm</a> an Emacs Cider front-end with support for Clojure and ClojureScript.</p>
</div>
</div>
<div class="sect2">
<h3 id="_vscode_2"><a class="anchor" href="#_vscode_2"></a><a class="link" href="#_vscode_2">22.2. VSCode</a></h3>
<div class="paragraph">
<p>With the following alias setup in deps.edn:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">{</span><span class="no">:aliases</span><span class="w"> </span><span class="p">{</span><span class="no">:flowstorm</span><span class="w"> </span><span class="p">{</span><span class="no">:classpath-overrides</span><span class="w"> </span><span class="p">{</span><span class="n">org.clojure/clojure</span><span class="w"> </span><span class="n">nil</span><span class="p">}</span><span class="w">
                       </span><span class="no">:extra-deps</span><span class="w"> </span><span class="p">{</span><span class="n">com.github.flow-storm/clojure</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"1.12.3-4"</span><span class="p">}</span><span class="w">
                                    </span><span class="n">com.github.flow-storm/flow-storm-dbg</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"4.5.9"</span><span class="p">}}</span><span class="w">
                       </span><span class="no">:jvm-opts</span><span class="w"> </span><span class="p">[</span><span class="s">"-Dflowstorm.startRecording=true"</span><span class="w">
                                  </span><span class="s">"-Dclojure.storm.intrumentEnable=true"</span><span class="w">
                                  </span><span class="s">"-Dclojure.storm.intrumentAutoPrefixes=true"</span><span class="p">]}}}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Create a custom connect sequence in the VSCode settings.json:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="json"><span class="p">{</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"flowstorm"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"projectType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"deps.edn"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"cljsType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"none"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"extraNReplMiddleware"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"flow-storm.nrepl.middleware/wrap-flow-storm"</span><span class="p">],</span><span class="w">
      </span><span class="nl">"afterCLJReplJackInCode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"((requiring-resolve 'flow-storm.storm-api/start-debugger))"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"menuSelections"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"cljAliases"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"flowstorm"</span><span class="p">]</span><span class="w">
      </span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Jack-in using the <code>flowstorm</code> sequence from the menu.</p>
</div>
</div>
<div class="sect2">
<h3 id="_intellij_idea_cursive"><a class="anchor" href="#_intellij_idea_cursive"></a><a class="link" href="#_intellij_idea_cursive">22.3. IntelliJ IDEA (Cursive)</a></h3>

</div>
</div>
</div>
<div class="sect1">
<h2 id="_tutorials_and_demos"><a class="anchor" href="#_tutorials_and_demos"></a><a class="link" href="#_tutorials_and_demos">23. Tutorials and demos</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://github.com/flow-storm/flow-storm-debugger?tab=readme-ov-file#some-demo-videos-newers-at-the-top" class="bare">https://github.com/flow-storm/flow-storm-debugger?tab=readme-ov-file#some-demo-videos-newers-at-the-top</a></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_known_limitations_and_issues"><a class="anchor" href="#_known_limitations_and_issues"></a><a class="link" href="#_known_limitations_and_issues">24. Known limitations and issues</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_code_with_macros_that_dont_preserve_meta"><a class="anchor" href="#_code_with_macros_that_dont_preserve_meta"></a><a class="link" href="#_code_with_macros_that_dont_preserve_meta">24.1. Code with macros that don&#8217;t preserve meta</a></h3>
<div class="paragraph">
<p>FlowStorm works fine with most macros, except the ones that don&#8217;t preserve meta at macroexpansion, which FlowStorm needs in their absence,
can cause GAPS IN EXECUTION TRACING AND PREVENT IT FROM LINKING THE EXECUTED CODE BACK TO THE ORIGINAL SOURCE.</p>
</div>
<div class="paragraph">
<p>When macros are involved, the forms compiled by the Clojure compiler aren&#8217;t the ones on your source files, but the ones generated
by macro-expanding all the macros. In order to link the compiled forms back to the forms in your source code, for each instrumented form,
right after the form is read by the reader, FlowStorm will walk the form down, annotating with meta each sub-form with a coordinate,
which will then be used after macro expansion to link a compiled expression back to your source code.</p>
</div>
<div class="paragraph">
<p>Macros can be as simple as code reorganizing ones (like <code>&#8594;</code>, <code>when</code>, <code>and</code>, <code>defn</code>, etc) or whole compilers like <code>clojure.core.async/go</code> and
Electric, so it really depends on the macros.</p>
</div>
<div class="paragraph">
<p>If you see code inside a macro not being traced feel free to report an issue, there is nothing FlowStorm can do from its side but
we can work together with the macro developer making sure it preserves all meta after macro expansion, which sometimes may be possible.</p>
</div>
</div>
<div class="sect2">
<h3 id="_locals_pane_and_mutable_values"><a class="anchor" href="#_locals_pane_and_mutable_values"></a><a class="link" href="#_locals_pane_and_mutable_values">24.2. Locals pane and mutable values</a></h3>
<div class="paragraph">
<p>The Locals pane will show the value of each binding for a symbol AT BINDING TIME, which is the same thing
no matter where you are in the current block when working with immutable objects, BUT NOT WHEN WORKING WITH MUTABLE ONES.</p>
</div>
<div class="paragraph">
<p>If what was bound was mutable in any way, you will be seeing the value at binding time, and not at current time which
could cause some confusion.</p>
</div>
</div>
<div class="sect2">
<h3 id="_closed_over_bindings_arent_displayed_in_locals"><a class="anchor" href="#_closed_over_bindings_arent_displayed_in_locals"></a><a class="link" href="#_closed_over_bindings_arent_displayed_in_locals">24.3. Closed over bindings aren&#8217;t displayed in Locals</a></h3>
<div class="paragraph">
<p>The locals pane will only display bindings for the current function. Locals visible from the current function but not defined
in it (like in the case of closures) aren&#8217;t shown.</p>
</div>
</div>
<div class="sect2">
<h3 id="_dont_instrument_clojure_core_or_flowstorm_itself"><a class="anchor" href="#_dont_instrument_clojure_core_or_flowstorm_itself"></a><a class="link" href="#_dont_instrument_clojure_core_or_flowstorm_itself">24.4. Don&#8217;t instrument clojure.core or FlowStorm itself</a></h3>
<div class="paragraph">
<p>Currently we can&#8217;t instrument clojure.core or FlowStorm itself since they endup in infinite tracing recursions.
This can be solved, but it is currently a limitation.</p>
</div>
</div>
<div class="sect2">
<h3 id="_if_test_expressions_tracing_with_intrinsics"><a class="anchor" href="#_if_test_expressions_tracing_with_intrinsics"></a><a class="link" href="#_if_test_expressions_tracing_with_intrinsics">24.5. IF test expressions tracing with intrinsics</a></h3>
<div class="paragraph">
<p>When you have code like :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">foo</span><span class="w"> </span><span class="p">[</span><span class="o">^</span><span class="nb">long</span><span class="w"> </span><span class="n">l</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">zero?</span><span class="w"> </span><span class="n">l</span><span class="p">)</span><span class="w">
    </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w">
    </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="mi">2</span><span class="p">)))</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>because <code>l</code> is a primitive long, the compiler can replace the (zero? l) with intrinsics (LCONST_0, LCMP, IFNE) so the
(zero? l) isn&#8217;t a expression anymore, just a statement. In these cases you will see the if test return un-highlighted, but
you can still tell which branch the code went thru because the chosen branch will be the highlighted one.</p>
</div>
</div>
<div class="sect2">
<h3 id="_loading_an_entire_file_while_recording_records_some_weird_code"><a class="anchor" href="#_loading_an_entire_file_while_recording_records_some_weird_code"></a><a class="link" href="#_loading_an_entire_file_while_recording_records_some_weird_code">24.6. Loading an entire file while recording records some weird code</a></h3>
<div class="paragraph">
<p>This is because most editors, (specially via nrepl) eval some other code on your namespace in order to load the
contents of your file. If that namespace is instrumented this will be also recorded, even when it is probably not
of your interest.
This is harmless, just clear your recordings before running and recording anything else.</p>
</div>
<div class="paragraph">
<p>If you follow the best practice of start recording right before running the stuff you are interested in recording you
should never see this.</p>
</div>
</div>
<div class="sect2">
<h3 id="_macro_calls_tracing_code_you_dont_see_on_your_code"><a class="anchor" href="#_macro_calls_tracing_code_you_dont_see_on_your_code"></a><a class="link" href="#_macro_calls_tracing_code_you_dont_see_on_your_code">24.7. Macro calls tracing code you don&#8217;t see on your code</a></h3>
<div class="paragraph">
<p>When you are evaluating some code that macroexpands to a (do form-1 &#8230;&#8203; form-n) the compiler recursively calls eval on the
sub forms. Because it is tricky in the compiler to tell apart your original source form from the ones the macroexpansion returned
those form-1 to form-n get instrumented and then traced as if they were on your code.</p>
</div>
<div class="paragraph">
<p>The tricky part is related to tooling like IDEs sometimes wrapping your forms in some macros that expand to a (do form-1 &#8230;&#8203; form-n)
so we can&#8217;t simply stop instrumenting after that situation.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_troubleshooting"><a class="anchor" href="#_troubleshooting"></a><a class="link" href="#_troubleshooting">25. Troubleshooting</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_the_outputs_panel_doesnt_work"><a class="anchor" href="#_the_outputs_panel_doesnt_work"></a><a class="link" href="#_the_outputs_panel_doesnt_work">25.1. The outputs panel doesn&#8217;t work</a></h3>
<div class="paragraph">
<p>Checkout that you don&#8217;t have piggieback on the classpath dragged by some dependency. Currently
if piggieback is pressent FlowStorm will assume a ClojureScript repl in which the outputs panel
isn&#8217;t supported yet.</p>
</div>
</div>
<div class="sect2">
<h3 id="_run_with_jdk_11"><a class="anchor" href="#_run_with_jdk_11"></a><a class="link" href="#_run_with_jdk_11">25.2. Run with JDK 11</a></h3>
<div class="paragraph">
<p>FlowStorm UI requires JDK &gt;= 17. If you can&#8217;t upgrade your JDK you can still use it by downgrading JavaFx.</p>
</div>
<div class="paragraph">
<p>If that is the case add these dependencies to your alias :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="clojure"><span class="n">org.openjfx/javafx-controls</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"19.0.2"</span><span class="p">}</span><span class="w">
</span><span class="n">org.openjfx/javafx-base</span><span class="w">     </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"19.0.2"</span><span class="p">}</span><span class="w">
</span><span class="n">org.openjfx/javafx-graphics</span><span class="w"> </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"19.0.2"</span><span class="p">}</span><span class="w">
</span><span class="n">org.openjfx/javafx-web</span><span class="w">      </span><span class="p">{</span><span class="no">:mvn/version</span><span class="w"> </span><span class="s">"19.0.2"</span><span class="p">}</span></code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_internals_diagrams_and_documentation"><a class="anchor" href="#_internals_diagrams_and_documentation"></a><a class="link" href="#_internals_diagrams_and_documentation">26. Internals, diagrams and documentation</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>For people interested in enhancing, troubleshooting, fixing or just learning about FlowStorm internals take a look at here :</p>
</div>
<div class="paragraph">
<p><a href="https://github.com/flow-storm/flow-storm-debugger/blob/master/docs/dev_notes.md" class="bare">https://github.com/flow-storm/flow-storm-debugger/blob/master/docs/dev_notes.md</a></p>
</div>
<div class="paragraph">
<p>Some useful diagrams :</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://raw.githubusercontent.com/flow-storm/flow-storm-debugger/master/docs/high_level_diagram.svg" class="bare">https://raw.githubusercontent.com/flow-storm/flow-storm-debugger/master/docs/high_level_diagram.svg</a></p>
</li>
<li>
<p><a href="https://raw.githubusercontent.com/flow-storm/flow-storm-debugger/master/docs/timeline.svg" class="bare">https://raw.githubusercontent.com/flow-storm/flow-storm-debugger/master/docs/timeline.svg</a></p>
</li>
<li>
<p><a href="https://raw.githubusercontent.com/flow-storm/flow-storm-debugger/master/docs/run_configs.svg" class="bare">https://raw.githubusercontent.com/flow-storm/flow-storm-debugger/master/docs/run_configs.svg</a></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2025-12-05 12:31:45 -0300
</div>
</div>
</body>
</html>